class EntityEvents(object):
    __slots__ = ('_eventManager', '_debugger')

    def __init__(self):
        self._eventManager = EventManager()
        self._debugger = None
        return

    def _createEvent(self):
        return SafeEvent(self._eventManager)

    def _createSynchronousEvent(self):
        return SynchronousEvent(self._eventManager)

    def _createUnsafeEvent(self):
        return Event(self._eventManager)

    def _createContextEvent(self):
        return ContextEvent(self._eventManager)

    def clear(self):
        self._eventManager.clear()

    def destroy(self):
        self.clear()

    def debugEvents(self):
        self._debugger = EventsDebugger(self)
예제 #2
0
class TimerService(GameServiceBase):
    def __init__(self):
        super(TimerService, self).__init__()
        self.__manager = EventManager()
        self.eUpdate1Sec = Event(self.__manager)
        self.eUpdate = Event(self.__manager)
        self.__updateCallback = None
        self.__update1SecCallback = None
        return

    def afterLinking(self):
        self.__updateCallback = BigWorld.callback(0.1, self.__update)
        self.__update1SecCallback = BigWorld.callback(1.0, self.__update1Sec)

    def doLeaveWorld(self):
        BigWorld.cancelCallback(self.__update1SecCallback)
        BigWorld.cancelCallback(self.__updateCallback)

    def __update1Sec(self):
        self.eUpdate1Sec()
        self.__update1SecCallback = BigWorld.callback(1.0, self.__update1Sec)

    def __update(self):
        self.eUpdate()
        self.__updateCallback = BigWorld.callback(0.1, self.__update)

    def destroy(self):
        self.__manager.clear()
예제 #3
0
class AbstractContextMenuHandler(object):
    __metaclass__ = ABCMeta

    def __init__(self, cmProxy, ctx=None, handlers=None):
        self._eManager = EventManager()
        self.onContextMenuHide = Event(self._eManager)
        super(AbstractContextMenuHandler, self).__init__()
        self.__cmProxy = weakref.proxy(cmProxy)
        self.__handlers = handlers or {}
        self._initFlashValues(ctx)

    @property
    def app(self):
        return self.__cmProxy.app

    def fini(self):
        self._eManager.clear()
        self.__handlers = None
        self.__cmProxy = None
        self._clearFlashValues()

    def getOptions(self, ctx=None):
        return self._generateOptions(ctx)

    def onOptionSelect(self, optionId):
        if optionId in self.__handlers:
            return getattr(self, self.__handlers[optionId])()
        LOG_WARNING('Unknown context menu option', self, self.__cmProxy,
                    optionId)

    def _dispatchChanges(self, options):
        if self.__cmProxy is not None:
            self.__cmProxy._onOptionsChanged(options)

    @classmethod
    def _makeItem(cls,
                  optId,
                  optLabel=None,
                  optInitData=None,
                  optSubMenu=None):
        return {
            'id': optId,
            'label': optLabel,
            'initData': optInitData,
            'submenu': optSubMenu
        }

    def _makeSeparator(self):
        return self._makeItem(_SEPARATOR_ID)

    @abstractmethod
    def _generateOptions(self, ctx=None):
        raise NotImplementedError

    def _initFlashValues(self, ctx):
        pass

    def _clearFlashValues(self):
        pass
class AbstractContextMenuHandler(object):
    __metaclass__ = ABCMeta

    def __init__(self, cmProxy, ctx = None, handlers = None):
        self._eManager = EventManager()
        self.onContextMenuHide = Event(self._eManager)
        super(AbstractContextMenuHandler, self).__init__()
        self.__cmProxy = weakref.proxy(cmProxy)
        self.__handlers = handlers or {}
        self._initFlashValues(ctx)

    @property
    def app(self):
        return self.__cmProxy.app

    def fini(self):
        self._eManager.clear()
        self.__handlers = None
        self.__cmProxy = None
        self._clearFlashValues()
        return

    def getOptions(self, ctx = None):
        return self._generateOptions(ctx)

    def onOptionSelect(self, optionId):
        if optionId in self.__handlers:
            return getattr(self, self.__handlers[optionId])()
        LOG_WARNING('Unknown context menu option', self, self.__cmProxy, optionId)

    def _dispatchChanges(self, options):
        if self.__cmProxy is not None:
            self.__cmProxy._onOptionsChanged(options)
        return

    @classmethod
    def _makeItem(cls, optId, optLabel = None, optInitData = None, optSubMenu = None):
        return {'id': optId,
         'label': optLabel,
         'initData': optInitData,
         'submenu': optSubMenu}

    def _makeSeparator(self):
        return self._makeItem(_SEPARATOR_ID)

    @abstractmethod
    def _generateOptions(self, ctx = None):
        raise NotImplementedError

    def _initFlashValues(self, ctx):
        pass

    def _clearFlashValues(self):
        pass
예제 #5
0
class GameActionsManagerProxy(object):

    def __init__(self):
        self._entity = None
        self._subscription = None
        self._eManager = EventManager()
        self.eWaveAdded = Event(self._eManager)
        self.eWaveRemoved = Event(self._eManager)
        self.eWaveStateChanged = Event(self._eManager)
        self.eBomberStateChanged = Event(self._eManager)
        return

    @property
    def activeASWaves(self):
        if self._entity:
            return self._entity.activeASWaves
        return []

    def onManagerEnterWorld(self, entity):
        raise not self._entity or AssertionError('Attempt to override registered manager, old = {0}, new = {1}'.format(self._entity, entity))
        self._entity = entity
        self._subscribeOn(entity)

    def onManagerLeaveWorld(self, entity):
        raise self._entity is entity or AssertionError('Attempt to unregister unknown manager: {0}, registered: {1}'.format(entity, self._entity))
        self._unsubscribe()
        self._entity = None
        return

    def cleanup(self):
        self._eManager.clear()

    def _subscribeOn(self, entity):
        raise self._subscription is None or AssertionError('Attempt to override subscription')
        self._subscription = CompositeSubscription(EventSubscription(entity.eWaveAdded, self.eWaveAdded), EventSubscription(entity.eWaveRemoved, self.eWaveRemoved), EventSubscription(entity.eWaveStateChanged, self.eWaveStateChanged), EventSubscription(entity.eBomberStateChanged, self.eBomberStateChanged))
        self._subscription.subscribe()
        return

    def _unsubscribe(self):
        raise self._subscription or AssertionError('Subscription is None')
        self._subscription.unsubscribe()
        self._subscription = None
        return
예제 #6
0
class CalendarComponent(CalendarMeta):
    def __init__(self):
        super(CalendarComponent, self).__init__()
        self.__em = EventManager()
        self.onMonthChangedEvent = Event(self.__em)
        self.onDateSelectedEvent = Event(self.__em)

    def onMonthChanged(self, timestamp):
        self.onMonthChangedEvent(timestamp)

    def onDateSelected(self, timestamp):
        self.onDateSelectedEvent(timestamp)

    def formatYMHeader(self, rawDate):
        return BigWorld.wg_getYMDateFormat(rawDate)

    def _dispose(self):
        self.__em.clear()
        super(CalendarComponent, self)._dispose()
예제 #7
0
class BasePublishPlatform(IPublishPlatform):
    __slots__ = ('__eventMgr', 'onPayment', 'onOverlay')

    def __init__(self):
        super(BasePublishPlatform, self).__init__()
        self.__eventMgr = EventManager()
        self.onPayment = Event(self.__eventMgr)
        self.onOverlay = Event(self.__eventMgr)

    def init(self):
        pass

    def fini(self):
        self.__eventMgr.clear()

    def isInited(self):
        return False

    def isConnected(self):
        return False
예제 #8
0
class CalendarComponent(CalendarMeta):

    def __init__(self):
        super(CalendarComponent, self).__init__()
        self.__em = EventManager()
        self.onMonthChangedEvent = Event(self.__em)
        self.onDateSelectedEvent = Event(self.__em)

    def onMonthChanged(self, timestamp):
        self.onMonthChangedEvent(timestamp)

    def onDateSelected(self, timestamp):
        self.onDateSelectedEvent(timestamp)

    def formatYMHeader(self, rawDate):
        return BigWorld.wg_getYMDateFormat(rawDate)

    def _dispose(self):
        self.__em.clear()
        super(CalendarComponent, self)._dispose()
예제 #9
0
class VehicleGroupBuilder(_EventsBlockBuilder):

    def __init__(self):
        super(VehicleGroupBuilder, self).__init__()
        self.__em = EventManager()
        self.onBlocksDataChanged = Event(self.__em)

    def init(self):
        super(VehicleGroupBuilder, self).init()
        g_currentVehicle.onChanged += self.__onVehicleChanged

    def clear(self):
        super(VehicleGroupBuilder, self).clear()
        g_currentVehicle.onChanged -= self.__onVehicleChanged
        self.__em.clear()

    def _getDefaultBlocks(self):
        return [_VehicleQuestsBlockInfo()]

    def __onVehicleChanged(self):
        self.onBlocksDataChanged()
예제 #10
0
class VehicleGroupFinder(_EventsBlockBuilder):
    """
    Build and collect block with server events data for current vehicle tab on mission page
    """
    def __init__(self):
        super(VehicleGroupFinder, self).__init__()
        self.__em = EventManager()
        self.onBlocksDataChanged = Event(self.__em)

    def init(self):
        super(VehicleGroupFinder, self).init()
        g_currentVehicle.onChanged += self.__onVehicleChanged

    def clear(self):
        super(VehicleGroupFinder, self).init()
        g_currentVehicle.onChanged -= self.__onVehicleChanged
        self.__em.clear()

    def _getDefaultBlocks(self):
        return [_VehicleQuestsBlockInfo()]

    def __onVehicleChanged(self):
        self.onBlocksDataChanged()
class ScaleformTutorialManager(TutorialManagerMeta):
    def __init__(self):
        super(ScaleformTutorialManager, self).__init__()
        self.__eventMgr = EventManager()
        self.onComponentFoundEvent = Event(self.__eventMgr)
        self.onComponentDisposedEvent = Event(self.__eventMgr)
        self.onTriggerActivatedEvent = Event(self.__eventMgr)
        self.onEffectCompletedEvent = Event(self.__eventMgr)

    def _dispose(self):
        self.__eventMgr.clear()
        super(ScaleformTutorialManager, self)._dispose()

    def onComponentFound(self, componentId, viewTutorialId):
        self.onComponentFoundEvent(componentId, viewTutorialId)

    def onTriggerActivated(self, componentId, triggerId, state):
        self.onTriggerActivatedEvent(componentId, triggerId, state)

    def onComponentDisposed(self, componentId):
        self.onComponentDisposedEvent(componentId)

    def onEffectCompleted(self, componentId, effectType):
        self.onEffectCompletedEvent(componentId, effectType)
예제 #12
0
class TeamObject(BigWorld.Entity, ControllerManager, CollidableObject):
    def __init__(self):
        ControllerManager.__init__(self)
        CollidableObject.__init__(self)
        self._logger = BWLogging.getLogger(self)
        self.filter = BigWorld.AvatarFilter()
        self._settings = None
        self.alignToGround = False
        self.__addedToArena = False
        self.__teamObjectArenaData = None
        self.vscriptStarted = False
        self.syncedRandom = SyncedRandom()
        return

    def updateLocalizedName(self):
        self.localizedName = localizeObject(self._settings.name)

    def onMapEntryCreated(self, mapEntry):
        pass

    @property
    def mapMatrix(self):
        return self.matrix

    def onEnterWorld(self, prereqs):
        self.setGameTeamIndex(self.teamIndex)
        self._initDBSettings()
        self.prepareMatrices()
        self.__createEvents()
        self._createControllers()
        movementStrategy = self.controllers.get('movementStrategy', None)
        if hasattr(self._settings, 'alignToGround'):
            self.alignToGround = self._settings.alignToGround
        if movementStrategy and movementStrategy.matrixProvider:
            self.filter = movementStrategy.createFilter()
        elif self.alignToGround:
            self.filter = BigWorld.AvatarDropFilter()
            self.filter.alignToGround = True
        elif self.filter.__class__ != BigWorld.PredictionFilter:
            self.filter = BigWorld.PredictionFilter()
        self.updateLocalizedName()
        self._checkStateSettings()
        self._notifyModelManipulatorOwnerChanged(self)
        self.controllers['modelManipulator'].updatePartsFlags(self.partFlags)
        self.controllers['modelManipulator'].updateStatesNet(
            self.partStates, True)
        self.eTeamIndexChanged += self.updateCompoundColour
        self.controllers[
            'modelManipulator'].eCompoundLoaded += self.updateCompoundColour
        self.updateCompoundColour()
        self.eOnTeamObjectEnterWorld(self)
        debug_observable.startObserv(self)
        return

    def _notifyModelManipulatorOwnerChanged(self, owner):
        modelManipulator = self.controllers.get('modelManipulator')
        if modelManipulator:
            modelManipulator.onOwnerChanged(owner)

    def __createEvents(self):
        self._eventManager = EventManager()
        self.ePartStateChanged = Event(self._eventManager)
        self.eHealthChanged = Event(self._eventManager)
        self.eTeamIndexChanged = Event(self._eventManager)
        self.eOnEntityStateChanged = Event(self._eventManager)
        self.eOnTeamObjectEnterWorld = Event(self._eventManager)
        self.eOnTeamObjectLeaveWorld = Event(self._eventManager)

    def _createControllers(self):
        controllersData = GameEnvironment.getClientArena(
        ).createTeamObjectControllers(self.id, self._settings, self,
                                      self.partTypes, self.partStates)
        modelManipulator = controllersData['modelManipulator']
        self._registerController('modelManipulator', modelManipulator)
        self.model = modelManipulator.getRootModel()
        self.model.delMotor(self.model.motors[0])
        self.model.addMotor(BigWorld.Servo(self.resMatrix))
        modelManipulator.setMatrixProvider(self.resMatrix)
        turretsLogic = controllersData.get('turretsLogic', None)
        if turretsLogic:
            turretsLogic.setOwner(self)
            self._registerController('turretsLogic', turretsLogic)
            self.ePartStateChanged += turretsLogic.onPartStateChanged
        if self.scenarioName != '':
            if not self.scenarioName.endswith(
                    '.xml') and not self.scenarioName.endswith('.plan'):
                scenarioData = db.DBLogic.g_instance.getScenario(
                    self.scenarioName)
                if scenarioData:
                    scenarioController = TeamObjectScenarioController(
                        self, scenarioData)
                    self._registerController('scenarioController',
                                             scenarioController)
                else:
                    LOG_ERROR("Can't find scenario", self.scenarioName)
        soundController = controllersData['soundController']
        self._registerController('soundController', soundController)
        return

    def isPlayer(self):
        return False

    def getSuperiorityPointsByGroupPartId(self, groupID):
        return getattr(self._settings, 'superiorityPointsGroup%d' % groupID, 0)

    def set_partFlags(self, changesData):
        self.controllers['modelManipulator'].updatePartsFlags(self.partFlags)
        self.controllers['soundController'].updatePartsFlags(self.partFlags)

    def setNested_partStates(self, path, value):
        item = self.partStates[path[0]]
        part = TODummyPart(self._settings.partsSettings, item[0], item[1])
        self.ePartStateChanged(part)
        if self.__addedToArena:
            isDead = self.__isPartDead(part.partTypeData, item[1])
            GameEnvironment.g_instance.eTOPartChanged(self.id, item[0], isDead)
        self.set_partStates(None)
        return

    def set_partStates(self, oldPartStates):
        modelManipulator = self.controllers.get('modelManipulator', None)
        if modelManipulator:
            modelManipulator.velocity = self.getWorldVector()
            modelManipulator.updateStatesNet(self.partStates, True)
        if EntityStates.inState(self, EntityStates.GAME_CONTROLLED):
            player = BigWorld.player()
            if self.lastDamagerID == player.id and self.teamIndex != player.teamIndex and self.teamIndex <= 1:
                for partID, partState in self.partStates:
                    if partID == self.lastDamagedPartID:
                        if partState >= 4:
                            reportedIDs = player.reportedDamagedPartsByEntity.get(
                                self.id, None)
                            if reportedIDs:
                                if self.lastDamagedPartID in reportedIDs and reportedIDs[
                                        self.lastDamagedPartID] == partState:
                                    break
                                else:
                                    reportedIDs[
                                        self.lastDamagedPartID] = partState
                            else:
                                player.reportedDamagedPartsByEntity[
                                    self.id] = {
                                        self.lastDamagedPartID: partState
                                    }
                        break

        self.__collisionStateUpdate(True)
        if oldPartStates is not None:
            for partID, partState in self.partStates:
                GameEnvironment.g_instance.eTOPartChanged(
                    self.id, partID, False)

        return

    def _checkStateSettings(self, transtitionActions=False):
        if self.inWorld:
            self.setGameState(self.state)
            self.controllers['modelManipulator'].setState(
                self.state, transtitionActions)
            if EntityStates.inState(self, EntityStates.CREATED):
                self.onRespawn()
            elif EntityStates.inState(self, EntityStates.DESTROYED):
                if transtitionActions:
                    LOG_DEBUG(
                        'TeamObject::_checkStateSettings - For object %s set effects %s to self.position'
                        % (self._settings.name,
                           self._settings.damageEffects.destroy))
                    EffectManager.g_instance.createWorldEffect(
                        Effects.getEffectId(
                            self._settings.damageEffects.destroy),
                        self.position, {})
                self._clearFromArena(False)
        if EntityStates.inState(self,
                                EntityStates.GAME | EntityStates.WAIT_START):
            self._addToArena()
            self.controllers['modelManipulator'].setVisible(True)
        self.__collisionStateUpdate(True)
        if EntityStates.inState(self,
                                EntityStates.GAME) and not self.vscriptStarted:
            self.vscriptStarted = True
            BigWorld.startEntityScripts(self)
        if self.vscriptStarted and not EntityStates.inState(
                self, EntityStates.GAME):
            self.vscriptStarted = False
            BigWorld.stopEntityScripts(self)

    def __collisionStateUpdate(self, inWorld):
        needCollision = not EntityStates.inState(
            self, EntityStates.CREATED) and self.inWorld and inWorld
        if needCollision:
            self.startCollisionDetection()
        else:
            self.stopCollisionDetection()

    def onRespawn(self):
        LOG_TRACE('TeamObject: onRespawn', self.id)
        self.controllers['modelManipulator'].setVisible(False)
        self._clearFromArena(False)

    def set_state(self, oldValue):
        self._checkStateSettings(True)
        self.eOnEntityStateChanged(self.id, oldValue, self.state)

    def getWorldVector(self):
        return Math.Vector3()

    def getSpeed(self):
        return 0.0

    def prepareMatrices(self):
        scaleMatrix = Math.Matrix()
        scaleMatrix.setScale(
            (self._settings.modelScaling, self._settings.modelScaling,
             self._settings.modelScaling))
        self.modelTranslationsMatrix = Math.Matrix()
        productMatrix = Math.MatrixProduct()
        productMatrix.a = scaleMatrix
        productMatrix.b = None
        self.resMatrix = productMatrix
        self.targetMatrix = productMatrix
        return

    def setupMP(self, mp):
        self.resMatrix.b = mp

    def onLeaveWorld(self):
        self.eTeamIndexChanged -= self.updateCompoundColour
        self.controllers[
            'modelManipulator'].eCompoundLoaded -= self.updateCompoundColour
        self._notifyModelManipulatorOwnerChanged(None)
        self._eventManager.clear()
        self._clearFromArena(True)
        modelManipulator = self.controllers.get('modelManipulator', None)
        modelManipulator.setMatrixProvider(None)
        self._unregisterController('modelManipulator')
        turretsLogic = self.controllers.get('turretsLogic', None)
        if turretsLogic:
            turretsLogic.setOwner(None)
            self._unregisterController('turretsLogic')
        self._unregisterController('soundController')
        self._destroyControllers()
        self.model = None
        debug_observable.endObserv(self)
        self.__collisionStateUpdate(False)
        self.eOnTeamObjectLeaveWorld(BigWorld.player(), self.id, self)
        return

    def _addToArena(self):
        if not self.__addedToArena:
            self.__addedToArena = True
        GameEnvironment.g_instance.eAvatarAdded(self)

    def _clearFromArena(self, isLeaveWorld):
        if self.__addedToArena:
            self.__addedToArena = False
        GameEnvironment.g_instance.eAvatarRemoved(self, isLeaveWorld)

    def _directionOnCurrentEnemy(self):
        entity = BigWorld.entities.get(self.lastDamagerID, None)
        if entity:
            vector = entity.position - self.position
            vector.normalise()
            return vector
        else:
            return Math.Vector3(0, 1, 0)
            return

    def set_health(self, oldValue):
        if oldValue > self.health:
            GameEnvironment.g_instance.eAvatarHealthChange(self, oldValue)
        self.eHealthChanged(self.id, self.health, self.lastDamagerID, oldValue,
                            self.maxHealth)

    def getMapTexture(self):
        if self._settings.turretName:
            return HUD_MINIMAP_ENTITY_TYPE_TURRET
        if self._settings.type == TYPE_TEAM_OBJECT.BIG:
            return HUD_MINIMAP_ENTITY_TYPE_TEAM_OBJECT_BASE
        return self._settings.type == TYPE_TEAM_OBJECT.TURRET and HUD_MINIMAP_ENTITY_TYPE_TURRET or HUD_MINIMAP_ENTITY_TYPE_TEAM_OBJECT

    def _initDBSettings(self):
        arenaSettings = db.DBLogic.g_instance.getArenaData(
            BigWorld.player().arenaType)
        self.__teamObjectArenaData = arenaSettings.getTeamObjectData(
            self.arenaObjID)
        if self.__teamObjectArenaData:
            modelStrID = self.__teamObjectArenaData['modelID']
            self._settings = db.DBLogic.g_instance.getEntityDataByName(
                db.DBLogic.DBEntities.BASES, modelStrID)
            if self._settings:
                self.initPartsMap(self.settings.partsSettings)
            else:
                LOG_ERROR("Can't find settings for teamObject", modelStrID)
        else:
            LOG_ERROR("Can't find data for object", self.arenaObjID)

    @property
    def settings(self):
        return self._settings

    def set_isTurretFiring(self, oldValue):
        turretsLogic = self.controllers.get('turretsLogic', None)
        if turretsLogic:
            turretsLogic.onChangeFiring(self.isTurretFiring)
        return

    def set_turretShootSync(self, oldValue):
        LOG_DEBUG(' set_turretTest TO')
        turretsLogic = self.controllers.get('turretsLogic', None)
        if turretsLogic:
            turretsLogic.onChangeShootingSync(self.turretShootSync)
        return

    def addBullet(self,
                  startPos,
                  endPos,
                  bulletSpeed,
                  time,
                  gun,
                  explosionEffect,
                  delay=0,
                  gunID=0,
                  dPos=None):
        explosionF = None
        if explosionEffect:
            explosionF = partial(onBulletExplosion, explosionEffect, startPos)
        shellEffect = gun.shellPath != ''
        if shellEffect:
            tm = BigWorld.time()
            if tm - gun.shellSyncTime < gun.shellOutInterval:
                shellEffect = False
            else:
                gun.shellSyncTime = tm
        turretShotStartPos = self.controllers['modelManipulator'].onAddBullet(
            gunID, delay, shellEffect)
        bulletId = BigWorld.addBullet(
            startPos if turretShotStartPos is None else turretShotStartPos,
            endPos, bulletSpeed, time, gun.shootInfo.bulletRenderType,
            BULLET_PARAM.FOREIGN, explosionF)
        return bulletId

    def addInvisibleBullet(self, startPos, endPos, bulletSpeed, time, gun,
                           explosionEffect):
        if explosionEffect:
            explosionF = partial(onBulletExplosion, explosionEffect, startPos)
            return BigWorld.addBullet(startPos, endPos, bulletSpeed, time,
                                      gun.shootInfo.bulletRenderType,
                                      BULLET_PARAM.INVISIBLE, explosionF)

    def updateTurretsRotations(self, gunners):
        modelManipulator = self.controllers.get('modelManipulator', None)
        if modelManipulator:
            modelManipulator.setAxisValue(TURRET_TRACKER_AXIS, gunners)
        return

    def set_turretTargetID(self, oldData):
        turretsLogic = self.controllers.get('turretsLogic', None)
        if turretsLogic is not None:
            turretsLogic.eTurretTargetChanged(self.turretTargetID)
        soundController = self.controllers.get('soundController', None)
        if soundController:
            for gunnerId, _ in turretsLogic.gunners.iteritems():
                soundController.onTurretTargetChanged(gunnerId,
                                                      self.turretTargetID)

        return

    def set_timelinesTime(self, oldValue):
        """transfer timeLines state from Cell ScenarioControllerMaster to Client ScenarioControllerSlave"""
        scenarioController = self.controllers.get('scenarioController', None)
        if scenarioController:
            scenarioController.refreshTimelines(self.timelinesTime)
        return

    def set_curStrategyStartTime(self, prevValue):
        movementStrategy = self.controllers.get('movementStrategy', None)
        if movementStrategy:
            movementStrategy.setStartTime(self.curStrategyStartTime)
        return

    def set_curStrategyPausedAt(self, prevValue):
        movementStrategy = self.controllers.get('movementStrategy', None)
        if movementStrategy:
            movementStrategy.setPauseTime(self.curStrategyPausedAt)
        return

    def getDebugInfo(self):
        matrix = Math.Matrix(self.matrix)
        compoundID = self.controllers.get('modelManipulator', None).compoundID
        data = [('ID', self.id), ('Name', self.objectName),
                ('arenaObjID', self.arenaObjID),
                ('HP', str(self.health) + '/' + str(self.maxHealth)),
                ('typeName', self._settings.typeName),
                ('LOD', CompoundSystem.getCompoundLOD(compoundID)),
                ('Vis/Prim', '{0}/{1}'.format(self.model.visuals,
                                              self.model.primitives)),
                ('DistanceBW', (BigWorld.camera().position -
                                Math.Matrix(self.matrix).translation).length),
                ('Class', self.__class__.__name__),
                ('Parts', '{0}|{1}'.format(
                    len(self.partStates), ','.join([
                        '{0}:{1}'.format(pID, pValue)
                        for pID, pValue in self.partStates
                    ]))), ('State', EntityStates.getStateName(self.state)),
                ('YPR,S', '({0:.2},{1:.2},{2:.2}),{3:.3}'.format(
                    math.degrees(matrix.yaw), math.degrees(matrix.pitch),
                    math.degrees(matrix.roll),
                    math.pow(matrix.determinant, 1.0 / 3.0))),
                ('ACType',
                 SETTINGS.GROUND_OBJECT_TYPE.getName(self.areaConquestType))]
        if self.__teamObjectArenaData['DsName']:
            data.append(('DsName', self.__teamObjectArenaData['DsName']))
        if self.scenarioName:
            timeLineData = '{0}[{1}]'.format(
                self.scenarioName, ','.join([
                    '{0}:{1}'.format(
                        i,
                        int(BigWorld.serverTime() -
                            time) if time != -1 else 'N')
                    for i, time in enumerate(self.timelinesTime)
                ]))
            data.append(('scenarioName', timeLineData))
        return data

    def getDebugMarkerCaption(self):
        if not hasattr(self, 'teamIndex'):
            return '\\cFFFFFFCC; BAD OBJECT:\n NOT TEAM INDEX\n {id}'.format(
                id=self.id)
        healthText = '{health}/{maxHealth}'.format(health=int(self.health),
                                                   maxHealth=int(
                                                       self.maxHealth))
        if self.teamIndex == BigWorld.player().teamIndex:
            return '\\c0000FFCC; Friendly ground\n {id}\n{health}'.format(
                id=self.id, health=healthText)
        elif self.teamIndex == TEAM_ID.TEAM_2:
            return '\\cAA9900CC; Neutral ground\n {id}\n{health}'.format(
                id=self.id, health=healthText)
        else:
            return '\\cFF0000CC; Enemy ground\n {id}\n{health}'.format(
                id=self.id, health=healthText)

    def useCollisionModel(self):
        return False

    def getPartsTypeData(self, pID=None, isConsiderDead=False):
        partsData = list()
        if self.settings is not None:
            partStates = dict(self.partStates)
            for partTuple in self.settings.partsSettings.getPartsList():
                upgrade = None
                partID = partTuple[0]
                if pID is not None and pID != partID:
                    continue
                partDB = partTuple[1]
                for it in self.partTypes:
                    if it['key'] == partID:
                        upgrade = partDB.getPartType(it['value'])
                        break

                if not upgrade:
                    upgrade = partDB.getFirstPartType()
                if upgrade.bboxes.list:
                    isArmored = False
                    for bbox in upgrade.bboxes.list:
                        if bbox.absorption < 1:
                            isArmored = True
                            break

                    partState = partStates.get(partID, 1)
                    if partState in upgrade.states:
                        isDead = self.__isPartDead(upgrade, partState)
                        if not isDead or isConsiderDead:
                            partsData.append({
                                'isDead':
                                isDead,
                                'partId':
                                partID,
                                'isFiring':
                                upgrade.componentType == 'Gunner',
                                'isArmored':
                                isArmored
                            })
                    else:
                        LOG_WARNING(
                            'getPartsTypeData - partState not in states',
                            partID, partState, upgrade.states, partStates)

        else:
            LOG_ERROR('getPartsTypeData - settings is not loaded', self.id)
        return partsData

    def useAutoAimMode(self):
        return TEAM_OBJECT_AUTO_AIMING_ENABLED

    def __isPartDead(self, upgrade, partState):
        return upgrade.states[partState].stateHelthCfc == 0

    def isPartStateAimable(self, presentPartsMap, partID, state):
        return presentPartsMap[partID].states[state].stateHelthCfc > 0

    def sendCustomEventToCell(self, eventName, planName, paramList):
        self.cell.customEventFromClient(eventName, planName, paramList)

    def customEventFromCell(self, eventName, planName, paramList):
        BigWorld.passEventToVisualScript(self, eventName, planName, paramList)

    def globalEventFromCell(self, eventName, channelList, paramList,
                            aspectsList):
        pass

    def updateCompoundColour(self, *args, **kwargs):
        """Update compound colour based on team index. Called on enter world,
        on ModelManipulator3.eCompoundLoaded and on TeamObject.eTeamIndexChanged events
        """
        self._logger.debug('updateCompoundColour: teamIndex={0}'.format(
            self.teamIndex))
        modelManipulator = self.controllers.get('modelManipulator')
        if not modelManipulator:
            self._logger.warning(
                'updateCompoundColour: modelManipulator not found')
            return
        compoundID = modelManipulator.compoundID
        if not CompoundSystem.isHandleValid(compoundID):
            self._logger.debug(
                'updateCompoundColour: invalid compoundID'.format(
                    self.teamIndex))
            return
        if self.teamIndex == TEAM_ID.TEAM_2:
            pick = SETTINGS.TEAM_OBJECTS_PAINTING.NEUTRAL_INDEX
        else:
            player = BigWorld.player()
            if self.teamIndex == player.teamIndex:
                pick = SETTINGS.TEAM_OBJECTS_PAINTING.ALLY_INDEX
            else:
                pick = SETTINGS.TEAM_OBJECTS_PAINTING.ENEMY_INDEX
        tilesCount = SETTINGS.TEAM_OBJECTS_PAINTING.TILES_COUNT
        CompoundSystem.setCompoundPick(compoundID, tilesCount, pick)

    def set_teamIndex(self, oldValue):
        self.eTeamIndexChanged(self.teamIndex)
        self.setGameTeamIndex(self.teamIndex)
예제 #13
0
class _CachedVehicle(object):

    def __init__(self):
        self._eManager = EventManager()
        self.onChanged = Event(self._eManager)
        self.onChangeStarted = Event(self._eManager)
        self.__changeCallbackID = None
        return

    def init(self):
        self._addListeners()

    def destroy(self):
        self._eManager.clear()
        self._clearChangeCallback()
        self._removeListeners()

    def selectVehicle(self, vehID):
        raise NotImplementedError

    def selectNoVehicle(self):
        raise NotImplementedError

    def isPresent(self):
        return self.item is not None

    def onInventoryUpdate(self, invDiff):
        raise NotImplementedError

    def refreshModel(self):
        raise NotImplementedError

    @property
    def item(self):
        raise NotImplementedError

    @property
    def invID(self):
        raise NotImplementedError

    @property
    def hangarSpace(self):
        return _getHangarSpace()

    def _addListeners(self):
        g_clientUpdateManager.addCallbacks({'inventory': self.onInventoryUpdate})

    def _removeListeners(self):
        g_clientUpdateManager.removeObjectCallbacks(self)

    def _changeDone(self):
        self._clearChangeCallback()
        if isPlayerAccount():
            self.onChanged()
        Waiting.hide('updateCurrentVehicle')

    def _setChangeCallback(self):
        if not self.__changeCallbackID:
            self.__changeCallbackID = BigWorld.callback(0.2, self._changeDone)

    def _clearChangeCallback(self):
        if self.__changeCallbackID is not None:
            BigWorld.cancelCallback(self.__changeCallbackID)
            self.__changeCallbackID = None
        return

    def _selectVehicle(self, vehID):
        raise NotImplementedError
예제 #14
0
class _PreDefinedHostList(object):

    def __init__(self):
        super(_PreDefinedHostList, self).__init__()
        self._eManager = EventManager()
        self.onCsisQueryStart = Event(self._eManager)
        self.onCsisQueryComplete = Event(self._eManager)
        self._hosts = []
        self._urlMap = {}
        self._nameMap = {}
        self._peripheryMap = {}
        self._isDataLoaded = False
        self._isCSISQueryInProgress = False
        self.__pingResult = {}
        self.__csisUrl = ''
        self.__csisResponse = {}
        self.__lastRoamingHosts = []
        self.__csisCallbackID = None
        self.__lastCsisUpdateTime = 0
        self.__queryCallback = None
        self.__autoLoginQueryState = AUTO_LOGIN_QUERY_STATE.DEFAULT
        self.__csisAction = CSIS_ACTION.DEFAULT
        self.__recommended = []
        self.__setPingCallback = False
        try:
            BigWorld.WGPinger.setOnPingCallback(self.__onPingPerformed)
            self.__setPingCallback = True
        except AttributeError:
            LOG_CURRENT_EXCEPTION()

        return

    def fini(self):
        self._hosts = []
        self._urlMap.clear()
        self._nameMap.clear()
        self._peripheryMap.clear()
        self._isDataLoaded = False
        self.__pingResult.clear()
        self.__csisResponse.clear()
        self.__csisUrl = ''
        self.__lastCsisUpdateTime = None
        self.__queryCallback = None
        self.__autoLoginQueryState = AUTO_LOGIN_QUERY_STATE.DEFAULT
        self.__csisAction = CSIS_ACTION.DEFAULT
        self._eManager.clear()
        self.__setPingCallback = False
        self.__cleanCsisTimerCallback()
        try:
            BigWorld.WGPinger.clearOnPingCallback()
        except AttributeError:
            LOG_CURRENT_EXCEPTION()

        return

    @property
    def lastRoamingHosts(self):
        return self.__lastRoamingHosts

    def startCSISUpdate(self):
        if len(self.hosts()) > 1:
            self.__csisAction = CSIS_ACTION.addIfNot(self.__csisAction, CSIS_ACTION.UPDATE_ON_TIME)
            self.__sendCsisQuery()

    def stopCSISUpdate(self):
        self.__csisAction = CSIS_ACTION.removeIfHas(self.__csisAction, CSIS_ACTION.UPDATE_ON_TIME)
        self.__cleanCsisTimerCallback()

    def autoLoginQuery(self, callback):
        if callback is None:
            LOG_WARNING('Callback is not defined.')
            return
        elif self.__autoLoginQueryState != AUTO_LOGIN_QUERY_STATE.DEFAULT:
            LOG_WARNING('Auto login query in process.')
            return
        elif len(self._hosts) < 2:
            callback(self.first())
            return
        else:
            peripheryID, expired = self.readPeripheryTL()
            if peripheryID > 0 and expired > 0:
                if expired > time.time():
                    host = self.periphery(peripheryID)
                    if host is not None:
                        LOG_DEBUG('Recommended host taken from cache', host)
                        callback(host)
                        return
            if len(self.__recommended):
                LOG_DEBUG('Gets recommended from previous query', self.__recommended)
                host = self.__choiceFromRecommended()
                LOG_DEBUG('Recommended host', host)
                callback(host)
                return
            self.__autoLoginQueryState = AUTO_LOGIN_QUERY_STATE.START
            self.__queryCallback = callback
            self.__ping()
            self.__csisAction = CSIS_ACTION.addIfNot(self.__csisAction, CSIS_ACTION.AUTO_LOGIN_REQUEST)
            self.__sendCsisQuery()
            return

    def resetQueryResult(self):
        self.__recommended = []
        self.__pingResult.clear()

    def savePeripheryTL(self, peripheryID, delta = STORED_AS_RECOMMEND_DELTA):
        if not AUTO_LOGIN_QUERY_ENABLED or not peripheryID:
            return
        else:
            try:
                loginSec = Settings.g_instance.userPrefs[Settings.KEY_LOGIN_INFO]
                if loginSec is not None:
                    value = base64.b64encode(pickle.dumps((peripheryID, time.time() + delta)))
                    loginSec.writeString('peripheryLifeTime', value)
                    Settings.g_instance.save()
            except Exception:
                LOG_CURRENT_EXCEPTION()

            return

    def readPeripheryTL(self):
        if not AUTO_LOGIN_QUERY_ENABLED:
            return (0, 0)
        else:
            result = (0, 0)
            try:
                loginSec = Settings.g_instance.userPrefs[Settings.KEY_LOGIN_INFO]
                if loginSec is not None:
                    value = loginSec.readString('peripheryLifeTime')
                    if len(value):
                        value = pickle.loads(base64.b64decode(value))
                        if len(value) > 1:
                            result = value
            except Exception:
                result = ('', 0)
                LOG_CURRENT_EXCEPTION()

            return result

    def clearPeripheryTL(self):
        if not AUTO_LOGIN_QUERY_ENABLED:
            return
        else:
            try:
                loginSec = Settings.g_instance.userPrefs[Settings.KEY_LOGIN_INFO]
                if loginSec is not None:
                    loginSec.writeString('peripheryLifeTime', '')
                    Settings.g_instance.save()
            except Exception:
                LOG_CURRENT_EXCEPTION()

            return

    def readScriptConfig(self, dataSection):
        if self._isDataLoaded or dataSection is None:
            return
        else:
            self.__csisUrl = dataSection.readString('csisUrl')
            self._hosts = []
            self._urlMap.clear()
            self._nameMap.clear()
            self._peripheryMap.clear()
            loginSection = dataSection['login']
            if loginSection is None:
                return
            for name, subSec in loginSection.items():
                name = subSec.readString('name')
                shortName = subSec.readString('short_name')
                urls = _LoginAppUrlIterator(subSec.readStrings('url'))
                host = urls.primary
                if host is not None:
                    if not len(name):
                        name = host
                    keyPath = subSec.readString('public_key_path')
                    if not len(keyPath):
                        keyPath = None
                    areaID = subSec.readString('game_area_id')
                    if not len(areaID):
                        areaID = None
                    app = self._makeHostItem(name, shortName, host, urlToken=subSec.readString('url_token'), urlIterator=urls if len(urls) > 1 else None, keyPath=keyPath, areaID=areaID, peripheryID=subSec.readInt('periphery_id', 0))
                    idx = len(self._hosts)
                    url = app.url
                    if url in self._urlMap:
                        LOG_ERROR('Host url is already added. This host is ignored', url)
                        continue
                    self._urlMap[url] = idx
                    urlToken = app.urlToken
                    if len(urlToken):
                        if urlToken in self._urlMap:
                            LOG_ERROR('Alternative host url is already added. This url is ignored', app.url)
                        else:
                            self._urlMap[urlToken] = idx
                    self._nameMap[app.name] = idx
                    if app.peripheryID:
                        self._peripheryMap[app.peripheryID] = idx
                    self._hosts.append(app)

            self._isDataLoaded = True
            return

    def predefined(self, url):
        return url in self._urlMap

    def roaming(self, url):
        return url in [ p.url for p in self.roamingHosts() ]

    def first(self):
        if len(self._hosts):
            return self._hosts[0]
        return self._makeHostItem('', '', '')

    def byUrl(self, url):
        result = self._makeHostItem('', '', url)
        index = self._urlMap.get(url, -1)
        if index > -1:
            result = self._hosts[index]
        else:
            for host in self.roamingHosts():
                if host.url == url:
                    result = host

        return result

    def byName(self, name):
        result = self._makeHostItem(name, '', '')
        index = self._nameMap.get(name, -1)
        if index > -1:
            result = self._hosts[index]
        else:
            for host in self.roamingHosts():
                if host.name == name:
                    result = host

        return result

    def hosts(self):
        return self._hosts[:]

    def shortList(self):
        result = self.getSimpleHostsList(self._hosts)
        if AUTO_LOGIN_QUERY_ENABLED and len(result) > 1 and len(self.peripheries()) > 1:
            result.insert(0, (AUTO_LOGIN_QUERY_URL,
             i18n.makeString('#menu:login/auto'),
             HOST_AVAILABILITY.IGNORED,
             None))
        return result

    def getSimpleHostsList(self, hosts):
        result = []
        defAvail = HOST_AVAILABILITY.getDefault()
        predefined = tuple((host.url for host in self.peripheries()))
        isInProgress = self._isCSISQueryInProgress
        csisResGetter = self.__csisResponse.get
        for item in hosts:
            if item.url not in predefined:
                status = HOST_AVAILABILITY.IGNORED
            else:
                status = defAvail if isInProgress else csisResGetter(item.peripheryID, defAvail)
            result.append((item.url,
             item.name,
             status,
             item.peripheryID))

        return result

    def urlIterator(self, primary):
        result = None
        index = self._urlMap.get(primary, -1)
        if index > -1:
            result = self._hosts[index].urlIterator
        return result

    def periphery(self, peripheryID):
        if peripheryID in self._peripheryMap:
            index = self._peripheryMap[peripheryID]
            return self._hosts[index]
        else:
            roamingHosts = dict(((host.peripheryID, host) for host in self.roamingHosts()))
            if peripheryID in roamingHosts:
                return roamingHosts[peripheryID]
            return None

    def peripheries(self):
        return filter(lambda app: app.peripheryID, self._hosts)

    def roamingHosts(self):
        p = BigWorld.player()
        result = []
        if hasattr(p, 'serverSettings'):
            for peripheryID, name, shortName, host, keyPath in p.serverSettings['roaming'][3]:
                result.append(self._makeHostItem(name, shortName, host, keyPath=keyPath, peripheryID=peripheryID))

            self.__lastRoamingHosts = sorted(result, key=operator.itemgetter(0))
        return self.__lastRoamingHosts

    def hostsWithRoaming(self):
        predefined = tuple((host.url for host in self.peripheries()))
        hosts = self.peripheries()
        for h in self.roamingHosts():
            if h.url not in predefined:
                hosts.append(h)

        return hosts

    def isRoamingPeriphery(self, peripheryID):
        return peripheryID not in [ p.peripheryID for p in self.peripheries() ]

    def _makeHostItem(self, name, shortName, url, urlToken = '', urlIterator = None, keyPath = None, areaID = None, peripheryID = 0):
        if not len(shortName):
            shortName = name
        return _HostItem(name, shortName, url, urlToken, urlIterator, keyPath, areaID, peripheryID)

    def _determineRecommendHost(self):
        defAvail = HOST_AVAILABILITY.NOT_AVAILABLE
        pResGetter = self.__pingResult.get
        csisResGetter = self.__csisResponse.get
        queryResult = map(lambda host: (host, pResGetter(host.url, -1), csisResGetter(host.peripheryID, defAvail)), self.peripheries())
        self.__recommended = filter(lambda item: item[2] == HOST_AVAILABILITY.RECOMMENDED, queryResult)
        if not len(self.__recommended):
            self.__recommended = filter(lambda item: item[2] == HOST_AVAILABILITY.NOT_RECOMMENDED, queryResult)
        recommendLen = len(self.__recommended)
        if not recommendLen:
            if len(queryResult) > 1:
                LOG_DEBUG('List of recommended is empty. Gets host by ping')
                self.__recommended = self.__filterRecommendedByPing(queryResult)
                LOG_DEBUG('Recommended by ping', self.__recommended)
                result = self.__choiceFromRecommended()
            else:
                LOG_DEBUG('Gets first as recommended')
                result = self.first()
        else:
            LOG_DEBUG('Recommended by CSIS', self.__recommended)
            if recommendLen > 1:
                self.__recommended = self.__filterRecommendedByPing(self.__recommended)
                LOG_DEBUG('Recommended by ping', self.__recommended)
            result = self.__choiceFromRecommended()
        return result

    def __ping(self):
        if not self.__setPingCallback:
            self.__onPingPerformed([])
            return
        try:
            peripheries = map(lambda host: host.url, self.peripheries())
            LOG_DEBUG('Ping starting', peripheries)
            BigWorld.WGPinger.ping(peripheries)
        except (AttributeError, TypeError):
            LOG_CURRENT_EXCEPTION()
            self.__onPingPerformed([])

    def __onPingPerformed(self, result):
        LOG_DEBUG('Ping performed', result)
        try:
            self.__pingResult = dict(result)
            self.__autoLoginQueryCompleted(AUTO_LOGIN_QUERY_STATE.PING_PERFORMED)
        except Exception:
            LOG_CURRENT_EXCEPTION()
            self.__pingResult = {}

    def __startCsisTimer(self):
        self.__cleanCsisTimerCallback()
        self.__csisCallbackID = BigWorld.callback(CSIS_REQUEST_TIMER, self.__onCsisTimer)

    def __cleanCsisTimerCallback(self):
        if self.__csisCallbackID:
            BigWorld.cancelCallback(self.__csisCallbackID)
            self.__csisCallbackID = None
        return

    def __onCsisTimer(self):
        self.__csisCallbackID = None
        self.__sendCsisQuery()
        return

    def __sendCsisQuery(self):
        if len(self.__csisUrl):
            if not self._isCSISQueryInProgress:
                timeFromLastUpdate = time.time() - self.__lastCsisUpdateTime
                if timeFromLastUpdate >= CSIS_REQUEST_TIMER:
                    self._isCSISQueryInProgress = True
                    self.onCsisQueryStart()
                    allHosts = self.hosts()
                    peripheries = map(lambda host: host.peripheryID, allHosts)
                    LOG_DEBUG('CSIS query sending', peripheries)
                    _CSISRequestWorker(self.__csisUrl, self.__receiveCsisResponse, peripheries).start()
                else:
                    self.__finishCsisQuery()
        else:
            LOG_DEBUG('CSIS url is not defined - ignore')
            self._isCSISQueryInProgress = False
            self.stopCSISUpdate()
            self.__finishCsisQuery()
            self.__lastCsisUpdateTime = 0

    def __receiveCsisResponse(self, response):
        LOG_DEBUG('CSIS query received', response)
        self._isCSISQueryInProgress = False
        self.__csisResponse = response
        self.__lastCsisUpdateTime = time.time()
        self.__finishCsisQuery()

    def __finishCsisQuery(self):
        if self.__csisAction & CSIS_ACTION.AUTO_LOGIN_REQUEST:
            self.__receiveAutoLoginCSISResponse(self.__csisResponse)
        if self.__csisAction & CSIS_ACTION.UPDATE_ON_TIME:
            self.__startCsisTimer()
        self.onCsisQueryComplete(self.__csisResponse)

    def __receiveAutoLoginCSISResponse(self, response):
        self.__csisAction = CSIS_ACTION.removeIfHas(self.__csisAction, CSIS_ACTION.AUTO_LOGIN_REQUEST)
        self.__autoLoginQueryCompleted(AUTO_LOGIN_QUERY_STATE.CSIS_RESPONSE_RECEIVED)

    def __autoLoginQueryCompleted(self, state):
        if not self.__autoLoginQueryState & state:
            self.__autoLoginQueryState |= state
        if self.__autoLoginQueryState == AUTO_LOGIN_QUERY_STATE.COMPLETED:
            host = self._determineRecommendHost()
            LOG_DEBUG('Recommended host', host)
            self.__autoLoginQueryState = AUTO_LOGIN_QUERY_STATE.DEFAULT
            self.__queryCallback(host)
            self.__queryCallback = None
        return

    def __filterRecommendedByPing(self, recommended):
        result = recommended
        filtered = filter(lambda item: item[1] > -1, recommended)
        if len(filtered):
            minPingTime = min(filtered, key=lambda item: item[1])[1]
            maxPingTime = 1.2 * minPingTime
            result = filter(lambda item: item[1] < maxPingTime, filtered)
        return result

    def __choiceFromRecommended(self):
        recommended = random.choice(self.__recommended)
        self.__recommended = filter(lambda item: item != recommended, self.__recommended)
        return recommended[0]
class QuestProgressController(IArenaPeriodController, IArenaVehiclesController):
    eventsCache = dependency.descriptor(IEventsCache)
    lobbyContext = dependency.descriptor(ILobbyContext)

    def __init__(self):
        super(QuestProgressController, self).__init__()
        self._period = ARENA_PERIOD.IDLE
        self._endTime = 0
        self._length = 0
        self._callbackID = None
        self.__storage = {}
        self.__selectedQuest = None
        self.__eManager = EventManager()
        self.__battleCtx = None
        self.__isInited = False
        self.__inProgressQuests = {}
        self.__needToShowAnimation = False
        self.onConditionProgressUpdate = Event(self.__eManager)
        self.onHeaderProgressesUpdate = Event(self.__eManager)
        self.onFullConditionsUpdate = Event(self.__eManager)
        self.onQuestProgressInited = Event(self.__eManager)
        self.onShowAnimation = Event(self.__eManager)
        self.__lastSelectedQuestID = 0
        return

    def getInProgressQuests(self):
        return self.__inProgressQuests

    def hasQuestsToPerform(self):
        return bool(self.__inProgressQuests)

    def getSelectedQuest(self):
        return self.__selectedQuest

    def isInited(self):
        return self.__isInited

    def selectQuest(self, missionID):
        self.__selectedQuest = self.__inProgressQuests.get(missionID)
        AccountSettings.setSettings(LAST_SELECTED_PM_BRANCH, self.__selectedQuest.getPMType().branch)
        if self.__selectedQuest:
            self.__needToShowAnimation = self.__lastSelectedQuestID != self.__selectedQuest.getID()
        self.onFullConditionsUpdate()

    def invalidateArenaInfo(self):
        isPersonalMissionsEnabled = self.lobbyContext.getServerSettings().isPersonalMissionsEnabled
        if not self.__isInited:
            lastSelectedBranch = AccountSettings.getSettings(LAST_SELECTED_PM_BRANCH)
            personalMissions = self.eventsCache.getPersonalMissions()
            selectedMissionsIDs = self.__battleCtx.getSelectedQuestIDs()
            selectedMissionsInfo = self.__battleCtx.getSelectedQuestInfo() or {}
            if selectedMissionsIDs:
                missions = personalMissions.getAllQuests()
                for missionID in selectedMissionsIDs:
                    mission = missions.get(missionID)
                    if mission and not mission.isDisabled() and isPersonalMissionsEnabled(mission.getQuestBranch()):
                        pqState = selectedMissionsInfo.get(missionID, (0, PM_STATE.NONE))[1]
                        mission.updatePqStateInBattle(pqState)
                        self.__inProgressQuests[missionID] = mission
                        generalQuestID = mission.getGeneralQuestID()
                        if mission.getPMType().branch == lastSelectedBranch:
                            self.__selectedQuest = mission
                        self.__storage[generalQuestID] = BattleProgressStorage(generalQuestID, mission.getConditionsConfig(), mission.getConditionsProgress(), mission.isOneBattleQuest())

                if self.__selectedQuest is None:
                    self.__selectedQuest = first(self.__inProgressQuests.itervalues())
                self.__updateTimerConditions(sendDiff=False)
            self.__isInited = True
            if self.__selectedQuest:
                self.__lastSelectedQuestID = self.__selectedQuest.getID()
            self.onQuestProgressInited()
        return

    def startControl(self, battleCtx, arenaVisitor):
        self.__battleCtx = battleCtx

    def areQuestsEnabledForArena(self):
        return self.__battleCtx.areQuestsEnabledForArena()

    def stopControl(self):
        self._period = ARENA_PERIOD.IDLE
        self._endTime = 0
        self._length = 0
        self.__selectedQuest = None
        self.__battleCtx = None
        self.__storage.clear()
        self.__eManager.clear()
        self.__clearCallback()
        self.__inProgressQuests.clear()
        self.__isInited = False
        return

    def setPeriodInfo(self, period, endTime, length, additionalInfo):
        self.__updatePeriodInfo(period, endTime, length)

    def invalidatePeriodInfo(self, period, endTime, length, additionalInfo):
        self.__updatePeriodInfo(period, endTime, length)

    def getQuestFullData(self):
        selectedQuest = self.__selectedQuest
        if selectedQuest:
            formatter = self.__getFormatter(selectedQuest)
            return {'questName': selectedQuest.getUserName(),
             'questID': selectedQuest.getID(),
             'questIndexStr': str(selectedQuest.getInternalID()),
             'questIcon': RES_ICONS.getAllianceGoldIcon(selectedQuest.getMajorTag()),
             'headerProgress': formatter.headerFormat(),
             'bodyProgress': formatter.bodyFormat()}
        return {}

    def getQuestShortInfoData(self):
        selectedQuest = self.__selectedQuest
        return {'questName': selectedQuest.getUserName(),
         'questIndexStr': str(selectedQuest.getInternalID()),
         'questIcon': RES_ICONS.getAllianceGoldIcon(selectedQuest.getMajorTag())} if selectedQuest else {}

    def getQuestHeaderProgresses(self):
        formatter = self.__getFormatter(self.__selectedQuest)
        return formatter.headerFormat()

    def updateQuestProgress(self, questID, info):
        if questID in self.__storage:
            self.__storage[questID].update(info)
        else:
            _logger.error('Storage for quest:%s is not found.', questID)
        selectedQuest = self.__selectedQuest
        if selectedQuest is not None:
            storage = self.__storage[selectedQuest.getGeneralQuestID()]
            needHeaderResync = False
            for headerProgress in storage.getHeaderProgresses().itervalues():
                if headerProgress.isChanged():
                    needHeaderResync = True
                    headerProgress.markAsVisited()

            if needHeaderResync:
                self.onHeaderProgressesUpdate()
            for progressID, condProgress in storage.getChangedConditions().iteritems():
                condProgress.markAsVisited()
                self.onConditionProgressUpdate(progressID, condProgress.getProgress())

        return

    def getControllerID(self):
        return BATTLE_CTRL_ID.QUEST_PROGRESS

    def getCtrlScope(self):
        return _SCOPE.PERIOD | _SCOPE.VEHICLES

    def showQuestProgressAnimation(self):
        if self.__needToShowAnimation:
            self.onShowAnimation()
            self.__needToShowAnimation = False
            if self.__selectedQuest:
                self.__lastSelectedQuestID = self.__selectedQuest.getID()

    def __updatePeriodInfo(self, period, endTime, length):
        self._period = period
        self._endTime = endTime
        self._length = length
        self.__clearCallback()
        if self._period == ARENA_PERIOD.BATTLE:
            self.__setCallback()

    def __setCallback(self):
        self._callbackID = None
        battleEndLeftTime = self._endTime - BigWorld.serverTime()
        tickInterval = 1 if battleEndLeftTime > 1 else 0
        self.__updateTimerConditions()
        self._callbackID = BigWorld.callback(tickInterval, self.__setCallback)
        return

    def __clearCallback(self):
        if self._callbackID is not None:
            BigWorld.cancelCallback(self._callbackID)
            self._callbackID = None
        return

    def __updateTimerConditions(self, sendDiff=True):
        selectedQuest = self.__selectedQuest
        if self._period == ARENA_PERIOD.BATTLE and selectedQuest:
            startTime = self._endTime - self._length
            timesGoneFromStart = BigWorld.serverTime() - startTime
            timerConditions = self.__storage[selectedQuest.getGeneralQuestID()].getTimerConditions()
            for progressID, condProgress in timerConditions.iteritems():
                secondsLeft = max(condProgress.getCountDown() - timesGoneFromStart, 0)
                isChanged = condProgress.setTimeLeft(secondsLeft)
                if isChanged and sendDiff:
                    self.onConditionProgressUpdate(progressID, condProgress.getProgress())

    def __getFormatter(self, selectedQuest):
        return DetailedProgressFormatter(self.__storage.get(selectedQuest.getGeneralQuestID()), selectedQuest)
예제 #16
0
class BuyBoosterMeta(I18nConfirmDialogMeta):
    goodiesCache = dependency.descriptor(IGoodiesCache)

    def __init__(self, boosterID, balance):
        super(BuyBoosterMeta,
              self).__init__('buyConfirmation',
                             scope=ScopeTemplates.LOBBY_SUB_SCOPE)
        self.__booster = self.goodiesCache.getBooster(boosterID)
        self.__balance = balance
        self._eManager = EventManager()
        self.onInvalidate = Event(self._eManager)
        g_clientUpdateManager.addCallbacks({'stats': self.__onStatsChanged})
        self.__boosterBuyPricesSum = self.__booster.buyPrices.getSum()

    def getEventType(self):
        return events.ShowDialogEvent.SHOW_CONFIRM_BOOSTER

    def getBoosterID(self):
        return self.__booster.boosterID

    def getBooster(self):
        return self.__booster

    def destroy(self):
        self.__booster = None
        self.__balance = None
        self._eManager.clear()
        g_clientUpdateManager.removeObjectCallbacks(self)
        return

    def getMaxAvailableItemsCount(self):
        """
        Returns tuple that contains max counts of booster that the user can buy for the current balance. Currency
        index in the tuple corresponds to the default order (see Currency.ALL).
        :return: CurrencyCollection(namedtuple)
        """
        buyPrice = self.__boosterBuyPricesSum.price
        return CurrencyCollection(*(self.__getMaxCount(buyPrice, currency)
                                    for currency in Currency.ALL))

    def getActionVO(self):
        if self.__boosterBuyPricesSum.isActionPrice():
            return packActionTooltipData(ACTION_TOOLTIPS_TYPE.BOOSTER,
                                         str(self.__booster.boosterID), True,
                                         self.__boosterBuyPricesSum.price,
                                         self.__boosterBuyPricesSum.defPrice)
        else:
            return None

    def getCurrency(self):
        """
        Returns the original buy currency, see Currency enum.
        :return: string
        """
        return self.__booster.getBuyPrice(preferred=True).getCurrency(
            byWeight=True)

    def getPrices(self):
        """
        Returns all set currencies(prices) for buying the booster.
        Right now booster's price can be defined only in one currency (in the same time any booster can have an
        alternative price). So sum the original and the alternative price to have all set currencies in one place.
        Note that such logic will not work with compound prices (multi-currency price).
        :return: ItemPrices
        """
        return self.__booster.buyPrices

    @process('buyItem')
    def submit(self, count, currency):
        result = yield BoosterBuyer(self.__booster, count, currency).request()
        if len(result.userMsg):
            SystemMessages.pushI18nMessage(result.userMsg,
                                           type=result.sysMsgType)

    def __onStatsChanged(self, stats):
        newValues = Money.extractMoneyDict(stats)
        if newValues:
            self.__balance = self.__balance.replaceAll(newValues)
            self.onInvalidate()

    def __getMaxCount(self, boosterPrice, currency):
        result = 0
        if boosterPrice.get(currency, 0) > 0:
            result = math.floor(
                self.__balance.get(currency, 0) / boosterPrice.get(currency))
        return min(result, MAX_BOOSTERS_FOR_OPERATION)
예제 #17
0
class RefSystem(IRefSystemController):
    eventsCache = dependency.descriptor(IEventsCache)

    def __init__(self):
        super(RefSystem, self).__init__()
        self.__referrers = []
        self.__referrals = []
        self.__quests = []
        self.__xpPoolOfDeletedRals = 0
        self.__totalXP = 0
        self.__isTotallyCompleted = False
        self.__posByXPinTeam = 0
        self.__eventMgr = EventManager()
        self.onUpdated = Event(self.__eventMgr)
        self.onQuestsUpdated = Event(self.__eventMgr)
        self.onPlayerBecomeReferrer = Event(self.__eventMgr)
        self.onPlayerBecomeReferral = Event(self.__eventMgr)

    @storage_getter('users')
    def usersStorage(self):
        return None

    def fini(self):
        self.__referrers = None
        self.__referrals = None
        self.__eventMgr.clear()
        self.__clearQuestsData()
        super(RefSystem, self).fini()
        return

    def onLobbyStarted(self, ctx):
        g_clientUpdateManager.addCallbacks({'stats.refSystem': self.__onRefStatsUpdated})
        self.eventsCache.onSyncCompleted += self.__onEventsUpdated
        g_playerEvents.onShopResync += self.__onShopUpdated
        self.__update(g_itemsCache.items.stats.refSystem)
        self.__updateQuests()

    def onAvatarBecomePlayer(self):
        self.__stop()

    def onDisconnected(self):
        self.__stop()

    def getReferrers(self):
        return self.__referrers

    def getReferrals(self):
        return self.__referrals

    def getQuests(self):
        return self.__quests

    def isTotallyCompleted(self):
        return self.__isTotallyCompleted

    def getPosByXPinTeam(self):
        return self.__posByXPinTeam

    def getTotalXP(self):
        return self.__totalXP

    def getReferralsXPPool(self):
        result = self.__xpPoolOfDeletedRals
        for i in self.getReferrals():
            result += i.getXPPool()

        return result

    def getAvailableReferralsCount(self):
        return _getMaxNumberOfReferrals() - len(self.__referrals)

    def showTankmanAwardWindow(self, tankman, completedQuestIDs):
        LOG_DEBUG('Referrer has been get tankman award', tankman, completedQuestIDs)
        curXp, nextXp, _ = self.__getAwardParams(completedQuestIDs)
        shared_events.showAwardWindow(TankmanAward(tankman, curXp, nextXp))

    def showVehicleAwardWindow(self, vehicle, completedQuestIDs):
        LOG_DEBUG('Referrer has been get vehicle award', vehicle, completedQuestIDs)
        curXp, nextXp, isBoughtVehicle = self.__getAwardParams(completedQuestIDs)
        shared_events.showAwardWindow(VehicleAward(vehicle, isBoughtVehicle, curXp))

    def showCreditsAwardWindow(self, creditsValue, completedQuestIDs):
        if creditsValue > 0:
            LOG_DEBUG('Referrer has been get credits award', creditsValue, completedQuestIDs)
            shared_events.showAwardWindow(CreditsAward(creditsValue))

    @classmethod
    def getRefPeriods(cls):
        return _getRefSystemPeriods()

    @classmethod
    def getMaxReferralXPPool(cls):
        return _getMaxReferralXPPool()

    @classmethod
    def getMaxNumberOfReferrals(cls):
        return _getMaxNumberOfReferrals()

    @classmethod
    def isReferrer(cls):
        refSystemStats = g_itemsCache.items.stats.refSystem
        return refSystemStats.get('activeInvitations', 0) > 0 or len(refSystemStats.get('referrals', {})) > 0

    def showReferrerIntroWindow(self, invitesCount):
        g_eventBus.handleEvent(events.LoadViewEvent(VIEW_ALIAS.REFERRAL_REFERRER_INTRO_WINDOW, ctx={'invitesCount': invitesCount}), EVENT_BUS_SCOPE.LOBBY)
        self.onPlayerBecomeReferrer()

    def showReferralIntroWindow(self, nickname, isNewbie = False):
        g_eventBus.handleEvent(events.LoadViewEvent(VIEW_ALIAS.REFERRAL_REFERRALS_INTRO_WINDOW, ctx={'referrerName': nickname,
         'newbie': isNewbie}), EVENT_BUS_SCOPE.LOBBY)
        self.onPlayerBecomeReferral()

    def __stop(self):
        g_playerEvents.onShopResync -= self.__onShopUpdated
        self.eventsCache.onSyncCompleted -= self.__onEventsUpdated
        g_clientUpdateManager.removeObjectCallbacks(self)

    def __getAwardParams(self, completedQuestIDs):
        completedQuestID = completedQuestIDs.pop() if len(completedQuestIDs) else -1
        currentXP = nextXP = None
        for xp, quests in reversed(self.getQuests()):
            if completedQuestID in map(methodcaller('getID'), quests):
                currentXP = xp
                break
            else:
                nextXP = xp

        return (currentXP, nextXP, self.getReferralsXPPool() < self.getTotalXP())

    def __clearQuestsData(self):
        self.__quests = []
        self.__isTotallyCompleted = False
        self.__totalXP = 0

    def __update(self, data):
        self.__referrers = []
        self.__referrals = []
        self.__xpPoolOfDeletedRals = 0
        self.__posByXPinTeam = g_itemsCache.items.shop.refSystem['posByXPinTeam']
        storage = self.usersStorage
        userGetter = storage.getUser
        userSetter = storage.addUser
        storage.removeTags({USER_TAG.REFERRER, USER_TAG.REFERRAL})

        def updateUser(item, tags):
            dbID = item.getAccountDBID()
            user = userGetter(dbID)
            if user:
                user.addTags(tags)
                if USER_TAG.INVALID_NAME in user.getTags():
                    user.update(name=item.getNickName())
            else:
                userSetter(SharedUserEntity(dbID, name=item.getNickName(), tags=tags, clanInfo=ClanInfo(abbrev=item.getClanAbbrev())))

        for referrer in self.__buildReferrers(data):
            self.__referrers.append(referrer)
            updateUser(referrer, {USER_TAG.REFERRER})

        for referral in self.__buildReferrals(data):
            self.__referrals.append(referral)
            updateUser(referral, {USER_TAG.REFERRAL})

        self.onUpdated()
        g_messengerEvents.users.onUsersListReceived({USER_TAG.REFERRER, USER_TAG.REFERRAL})

    @classmethod
    def __makeRefItem(cls, dbID, **data):
        try:
            return _RefItem(dbID, **data)
        except:
            LOG_ERROR('There is error while building ref system item')
            LOG_CURRENT_EXCEPTION()

    def __buildReferrers(self, data):
        for key, item in (data.get('referrers') or {}).iteritems():
            referrer = self.__makeRefItem(key, **item)
            if referrer is not None:
                yield referrer

        return

    def __buildReferrals(self, data):
        for key, item in (data.get('referrals') or {}).iteritems():
            if key == 'xpPoolOfDeletedRals':
                self.__xpPoolOfDeletedRals = item
            else:
                referral = self.__makeRefItem(key, **item)
                if referral is not None:
                    yield referral

        return

    def __updateQuests(self):
        self.__clearQuestsData()
        refSystemQuests = self.eventsCache.getHiddenQuests(lambda x: x.getType() == EVENT_TYPE.REF_SYSTEM_QUEST)
        if refSystemQuests:
            self.__quests = self.__mapQuests(refSystemQuests.values())
            self.__totalXP, _ = self.__quests[-1]
            notCompleted = findFirst(lambda q: not q.isCompleted(), refSystemQuests.values())
            self.__isTotallyCompleted = notCompleted is None
        self.onQuestsUpdated()
        return

    @classmethod
    def __mapQuests(cls, events):
        result = defaultdict(list)
        for event in sorted(events, key=methodcaller('getID')):
            result[event.accountReqs.getConditions().find('refSystemRalXPPool').getValue()].append(event)

        return sorted(result.iteritems(), key=itemgetter(0))

    def __onRefStatsUpdated(self, diff):
        self.__update(g_itemsCache.items.stats.refSystem)

    def __onEventsUpdated(self):
        self.__updateQuests()

    def __onShopUpdated(self):
        self.__update(g_itemsCache.items.stats.refSystem)
        self.__updateQuests()
예제 #18
0
class DisposableEntity(object):
    def __init__(self):
        super(DisposableEntity, self).__init__()
        self.__eManager = EventManager()
        self.onCreate = Event(self.__eManager)
        self.onCreated = Event(self.__eManager)
        self.onDispose = Event(self.__eManager)
        self.onDisposed = Event(self.__eManager)
        self.__lcState = EntityState.UNDEFINED
        self.__postponedState = EntityState.UNDEFINED

    def getState(self):
        return self.__lcState

    def create(self):
        if self.__lcState in (EntityState.UNDEFINED, EntityState.DISPOSED):
            self.__changeStateTo(EntityState.CREATING)
            self.onCreate(self)
            self._populate()
            self.__changeStateTo(EntityState.CREATED)
            self.onCreated(self)
            self.__invalidatePostponedState()
        elif self.__lcState == EntityState.DISPOSING:
            LOG_DEBUG(
                'Create call is postponed for {} object. Disposing is in progress.'
                .format(self))
            self.__postponedState = EntityState.CREATING
        else:
            LOG_DEBUG('Entity {} is already created! Current state {}.'.format(
                self, self.__lcState))

    def validate(self, *args, **kwargs):
        if self.__lcState == EntityState.CREATED:
            self.__changeStateTo(EntityState.CREATING)
            self._invalidate(*args, **kwargs)
            self.__changeStateTo(EntityState.CREATED)
            self.__invalidatePostponedState()
        elif self.__lcState in (EntityState.UNDEFINED, EntityState.DISPOSING,
                                EntityState.DISPOSED):
            LOG_DEBUG(
                'Invalidate call is skipped because object {} is destroyed or has not been created yet. Current state {}.'
                .format(self, self.__lcState))
        else:
            LOG_DEBUG(
                'Invalidate call is skipped because initialization of object {} is in progress.'
                .format(self))

    def destroy(self):
        if self.__lcState in (EntityState.UNDEFINED, EntityState.CREATED):
            needToBeDisposed = self.__lcState == EntityState.CREATED
            self.__changeStateTo(EntityState.DISPOSING)
            self.onDispose(self)
            if needToBeDisposed:
                self._dispose()
            self._destroy()
            self.__changeStateTo(EntityState.DISPOSED)
            self.onDisposed(self)
            self.__eManager.clear()
            self.__invalidatePostponedState()
        elif self.__lcState == EntityState.CREATING:
            LOG_DEBUG(
                'Destroy call is postponed for {} object. Initialization is in progress'
                .format(self))
            self.__postponedState = EntityState.DISPOSING
        else:
            LOG_DEBUG(
                'Entity {} is already destroyed! Current state {}.'.format(
                    self, self.__lcState))

    def isDisposed(self):
        return self.__lcState in (EntityState.DISPOSING, EntityState.DISPOSED)

    def isCreated(self):
        return self.__lcState in (EntityState.CREATING, EntityState.CREATED)

    def _populate(self):
        pass

    def _invalidate(self, *args, **kwargs):
        pass

    def _dispose(self):
        pass

    def _destroy(self):
        pass

    def __changeStateTo(self, state):
        self.__lcState = state

    def __invalidatePostponedState(self):
        if self.__postponedState in (EntityState.DISPOSING,
                                     EntityState.DISPOSED):
            LOG_DEBUG('Call postponed destroy call for {}'.format(self))
            self.destroy()
        elif self.__postponedState in (EntityState.CREATING,
                                       EntityState.CREATED):
            LOG_DEBUG('Call postponed create call for {}'.format(self))
            self.create()
        self.__postponedState = EntityState.UNDEFINED
예제 #19
0
class _EventsCache(object):
    USER_QUESTS = (EVENT_TYPE.BATTLE_QUEST,
     EVENT_TYPE.TOKEN_QUEST,
     EVENT_TYPE.FORT_QUEST,
     EVENT_TYPE.PERSONAL_QUEST,
     EVENT_TYPE.POTAPOV_QUEST)
    SYSTEM_QUESTS = (EVENT_TYPE.REF_SYSTEM_QUEST,)

    def __init__(self):
        self.__waitForSync = False
        self.__invalidateCbID = None
        self.__cache = defaultdict(dict)
        self.__potapovHidden = {}
        self.__actionsCache = defaultdict(lambda : defaultdict(dict))
        self.__questsDossierBonuses = defaultdict(set)
        self.__random = RandomPQController()
        self.__fallout = FalloutPQController()
        self.__potapovComposer = _PotapovComposer(self.__random, self.__fallout)
        self.__questsProgress = QuestsProgressRequester()
        self.__companies = CompanyBattleController(self)
        self.__em = EventManager()
        self.onSyncStarted = Event(self.__em)
        self.onSyncCompleted = Event(self.__em)
        self.onSelectedQuestsChanged = Event(self.__em)
        self.onSlotsCountChanged = Event(self.__em)
        self.onProgressUpdated = Event(self.__em)
        return

    def init(self):
        self.__random.init()
        self.__fallout.init()

    def fini(self):
        self.__fallout.fini()
        self.__random.fini()
        self.__em.clear()
        self.__clearInvalidateCallback()

    def start(self):
        self.__companies.start()

    def stop(self):
        self.__companies.stop()

    def clear(self):
        self.stop()
        quests_caches.clearNavInfo()

    @property
    def waitForSync(self):
        return self.__waitForSync

    @property
    def falloutQuestsProgress(self):
        return self.__fallout.questsProgress

    @property
    def randomQuestsProgress(self):
        return self.__random.questsProgress

    @property
    def random(self):
        return self.__random

    @property
    def fallout(self):
        return self.__fallout

    @property
    def questsProgress(self):
        return self.__questsProgress

    @property
    def potapov(self):
        return self.__potapovComposer

    @property
    def companies(self):
        return self.__companies

    @async
    @process
    def update(self, diff = None, callback = None):
        if diff is not None:
            if diff.get('eventsData', {}).get(EVENT_CLIENT_DATA.INGAME_EVENTS):
                self.__companies.setNotificators()
        yield self.falloutQuestsProgress.request()
        yield self.randomQuestsProgress.request()
        yield self.__questsProgress.request()
        isNeedToInvalidate = True
        isNeedToClearItemsCaches = False

        def _cbWrapper(*args):
            self.__random.update(self, diff)
            self.__fallout.update(self, diff)
            callback(*args)

        if diff is not None:
            isQPUpdated = 'quests' in diff
            isEventsDataUpdated = ('eventsData', '_r') in diff or diff.get('eventsData', {})
            isNeedToInvalidate = isQPUpdated or isEventsDataUpdated
            hasVehicleUnlocks = False
            for intCD in diff.get('stats', {}).get('unlocks', set()):
                if getTypeOfCompactDescr(intCD) == GUI_ITEM_TYPE.VEHICLE:
                    hasVehicleUnlocks = True
                    break

            isNeedToClearItemsCaches = 'inventory' in diff and GUI_ITEM_TYPE.VEHICLE in diff['inventory'] or hasVehicleUnlocks
        if isNeedToInvalidate:
            self.__invalidateData(_cbWrapper)
            return
        else:
            if isNeedToClearItemsCaches:
                self.__clearQuestsItemsCache()
            _cbWrapper(True)
            return

    def getQuests(self, filterFunc = None):
        filterFunc = filterFunc or (lambda a: True)

        def userFilterFunc(q):
            return not q.isHidden() and filterFunc(q)

        return self._getQuests(userFilterFunc)

    def getGroups(self, filterFunc = None):
        svrGroups = self._getQuestsGroups(filterFunc)
        svrGroups.update(self._getActionsGroups(filterFunc))
        return svrGroups

    def getHiddenQuests(self, filterFunc = None):
        filterFunc = filterFunc or (lambda a: True)

        def hiddenFilterFunc(q):
            return q.isHidden() and filterFunc(q)

        return self._getQuests(hiddenFilterFunc)

    def getAllQuests(self, filterFunc = None, includePotapovQuests = False):
        return self._getQuests(filterFunc, includePotapovQuests)

    def getActions(self, filterFunc = None):
        filterFunc = filterFunc or (lambda a: True)

        def userFilterFunc(q):
            return filterFunc(q) and q.getType() != EVENT_TYPE.GROUP

        return self._getActions(userFilterFunc)

    def getEventBattles(self):
        battles = self.__getEventBattles()
        if len(battles):
            return EventBattles(battles.get('vehicleTags', set()), battles.get('vehicles', []), bool(battles.get('enabled', 0)), battles.get('arenaTypeID'))
        else:
            return EventBattles(set(), [], 0, None)
            return None

    def isEventEnabled(self):
        return len(self.__getEventBattles()) > 0

    def getEventVehicles(self):
        from gui.shared import g_itemsCache
        result = []
        for v in g_eventsCache.getEventBattles().vehicles:
            item = g_itemsCache.items.getItemByCD(v)
            if item.isInInventory:
                result.append(item)

        return sorted(result)

    def getEvents(self, filterFunc = None):
        svrEvents = self.getQuests(filterFunc)
        svrEvents.update(self.getActions(filterFunc))
        return svrEvents

    def getCurrentEvents(self):
        return self.getEvents(lambda q: q.getStartTimeLeft() <= 0 < q.getFinishTimeLeft())

    def getFutureEvents(self):
        return self.getEvents(lambda q: q.getStartTimeLeft() > 0)

    def getCompanyBattles(self):
        battle = self.__getCompanyBattlesData()
        startTime = battle.get('startTime', 0.0)
        finishTime = battle.get('finishTime', 0.0)
        return CompanyBattles(startTime=None if startTime is None else float(startTime), finishTime=None if finishTime is None else float(finishTime), peripheryIDs=battle.get('peripheryIDs', set()))

    def getFalloutConfig(self, battleType):
        return makeTupleByDict(FalloutConfig, self.__getFallout().get(battleType, {}))

    def getItemAction(self, item, isBuying = True, forCredits = False):
        result = []
        type = ACTION_MODIFIER_TYPE.DISCOUNT if isBuying else ACTION_MODIFIER_TYPE.SELLING
        itemTypeID = item.itemTypeID
        nationID = item.nationID
        intCD = item.intCD
        values = self.__actionsCache[ACTION_SECTION_TYPE.ALL][type].get(itemTypeID, {}).get(nationID, [])
        values += self.__actionsCache[ACTION_SECTION_TYPE.ALL][type].get(itemTypeID, {}).get(15, [])
        for (key, value), actionID in values:
            if item.isPremium and key in ('creditsPrice', 'creditsPriceMultiplier') and not forCredits:
                continue
            result.append((value, actionID))

        result.extend(self.__actionsCache[ACTION_SECTION_TYPE.ITEM][type].get(itemTypeID, {}).get(intCD, tuple()))
        return result

    def getRentAction(self, item, rentPackage):
        result = []
        type = ACTION_MODIFIER_TYPE.RENT
        itemTypeID = item.itemTypeID
        nationID = item.nationID
        intCD = item.intCD
        values = self.__actionsCache[ACTION_SECTION_TYPE.ALL][type].get(itemTypeID, {}).get(nationID, [])
        values += self.__actionsCache[ACTION_SECTION_TYPE.ALL][type].get(itemTypeID, {}).get(15, [])
        for (key, value), actionID in values:
            result.append((value, actionID))

        result.extend(self.__actionsCache[ACTION_SECTION_TYPE.ITEM][type].get(itemTypeID, {}).get((intCD, rentPackage), tuple()))
        return result

    def getEconomicsAction(self, name):
        result = self.__actionsCache[ACTION_SECTION_TYPE.ECONOMICS][ACTION_MODIFIER_TYPE.DISCOUNT].get(name, [])
        resultMult = self.__actionsCache[ACTION_SECTION_TYPE.ECONOMICS][ACTION_MODIFIER_TYPE.DISCOUNT].get('%sMultiplier' % name, [])
        return tuple(result + resultMult)

    def getCamouflageAction(self, vehicleIntCD):
        return tuple(self.__actionsCache[ACTION_SECTION_TYPE.CUSTOMIZATION][ACTION_MODIFIER_TYPE.DISCOUNT].get(vehicleIntCD, tuple()))

    def getEmblemsAction(self, group):
        return tuple(self.__actionsCache[ACTION_SECTION_TYPE.CUSTOMIZATION][ACTION_MODIFIER_TYPE.DISCOUNT].get(group, tuple()))

    def getQuestsDossierBonuses(self):
        return self.__questsDossierBonuses

    def getQuestsByTokenRequirement(self, token):
        result = []
        for q in self._getQuests(includePotapovQuests=True).itervalues():
            if token in map(lambda t: t.getID(), q.accountReqs.getTokens()):
                result.append(q)

        return result

    def getQuestsByTokenBonus(self, token):
        result = []
        for q in self._getQuests(includePotapovQuests=True).itervalues():
            for t in q.getBonuses('tokens'):
                if token in t.getTokens().keys():
                    result.append(q)
                    break

        return result

    def _getQuests(self, filterFunc = None, includePotapovQuests = False):
        result = {}
        groups = {}
        filterFunc = filterFunc or (lambda a: True)
        for qID, q in self.__getCommonQuestsIterator():
            if q.getType() == EVENT_TYPE.GROUP:
                groups[qID] = q
                continue
            if q.getDestroyingTimeLeft() <= 0:
                continue
            if not filterFunc(q):
                continue
            result[qID] = q

        if includePotapovQuests:
            for qID, q in self.potapov.getQuests().iteritems():
                if filterFunc(q):
                    result[qID] = q

        for gID, group in groups.iteritems():
            for qID in group.getGroupEvents():
                if qID in result:
                    result[qID].setGroupID(gID)

        children, parents = self._makeQuestsRelations(result)
        for qID, q in result.iteritems():
            if qID in children:
                q.setChildren(children[qID])
            if qID in parents:
                q.setParents(parents[qID])

        return result

    def _getQuestsGroups(self, filterFunc = None):
        filterFunc = filterFunc or (lambda a: True)
        result = {}
        for qID, q in self.__getCommonQuestsIterator():
            if q.getType() != EVENT_TYPE.GROUP:
                continue
            if not filterFunc(q):
                continue
            result[qID] = q

        return result

    def _getActions(self, filterFunc = None):
        filterFunc = filterFunc or (lambda a: True)
        actions = self.__getActionsData()
        result = {}
        groups = {}
        for aData in actions:
            if 'id' in aData:
                a = self._makeAction(aData['id'], aData)
                actionID = a.getID()
                if a.getType() == EVENT_TYPE.GROUP:
                    groups[actionID] = a
                    continue
                if not filterFunc(a):
                    continue
                result[actionID] = a

        for gID, group in groups.iteritems():
            for aID in group.getGroupEvents():
                if aID in result:
                    result[aID].setGroupID(gID)

        return result

    def _getActionsGroups(self, filterFunc = None):
        actions = self.__getActionsData()
        filterFunc = filterFunc or (lambda a: True)
        result = {}
        for aData in actions:
            if 'id' in aData:
                a = self._makeAction(aData['id'], aData)
                if a.getType() != EVENT_TYPE.GROUP:
                    continue
                if not filterFunc(a):
                    continue
                result[a.getID()] = a

        return result

    def _onResync(self, *args):
        self.__invalidateData()

    def _makeQuest(self, qID, qData, maker = _defaultQuestMaker, **kwargs):
        storage = self.__cache['quests']
        if qID in storage:
            return storage[qID]
        q = storage[qID] = maker(qID, qData, self.__questsProgress, **kwargs)
        return q

    def _makeAction(self, aID, aData):
        storage = self.__cache['actions']
        if aID in storage:
            return storage[aID]
        a = storage[aID] = createAction(aData.get('type', 0), aID, aData)
        return a

    @classmethod
    def _makeQuestsRelations(cls, quests):
        makeTokens = defaultdict(list)
        needTokens = defaultdict(list)
        for qID, q in quests.iteritems():
            if q.getType() != EVENT_TYPE.GROUP:
                tokens = q.getBonuses('tokens')
                if len(tokens):
                    for t in tokens[0].getTokens():
                        makeTokens[t].append(qID)

                for t in q.accountReqs.getTokens():
                    needTokens[qID].append(t.getID())

        children = defaultdict(dict)
        for parentID, tokensIDs in needTokens.iteritems():
            for tokenID in tokensIDs:
                children[parentID][tokenID] = makeTokens.get(tokenID, [])

        parents = defaultdict(dict)
        for parentID, tokens in children.iteritems():
            for tokenID, chn in tokens.iteritems():
                for childID in chn:
                    parents[childID][tokenID] = [parentID]

        return (children, parents)

    def __invalidateData(self, callback = lambda *args: None):
        self.__clearCache()
        self.__clearInvalidateCallback()
        self.__waitForSync = True
        self.onSyncStarted()

        def mergeValues(a, b):
            result = list(a)
            result.extend(b)
            return result

        for action in self.getActions().itervalues():
            for modifier in action.getModifiers():
                section = modifier.getSection()
                type = modifier.getType()
                itemType = modifier.getItemType()
                values = modifier.getValues(action)
                currentSection = self.__actionsCache[section][type]
                if itemType is not None:
                    currentSection = currentSection.setdefault(itemType, {})
                for k in values:
                    if k in currentSection:
                        currentSection[k] = mergeValues(currentSection[k], values[k])
                    else:
                        currentSection[k] = values[k]

        rareAchieves = set()
        invalidateTimeLeft = sys.maxint
        for q in self.getCurrentEvents().itervalues():
            dossierBonuses = q.getBonuses('dossier')
            if len(dossierBonuses):
                storage = self.__questsDossierBonuses[q.getID()]
                for bonus in dossierBonuses:
                    records = bonus.getRecords()
                    storage.update(records)
                    rareAchieves |= set((r for r in records if r[0] == ACHIEVEMENT_BLOCK.RARE))

            timeLeftInfo = q.getNearestActivityTimeLeft()
            if timeLeftInfo is not None:
                isAvailable, errorMsg = q.isAvailable()
                if not isAvailable:
                    if errorMsg in ('invalid_weekday', 'invalid_time_interval'):
                        invalidateTimeLeft = min(invalidateTimeLeft, timeLeftInfo[0])
                else:
                    intervalBeginTimeLeft, (intervalStart, intervalEnd) = timeLeftInfo
                    invalidateTimeLeft = min(invalidateTimeLeft, intervalBeginTimeLeft + intervalEnd - intervalStart)
            else:
                invalidateTimeLeft = min(invalidateTimeLeft, q.getFinishTimeLeft())

        g_rareAchievesCache.request(rareAchieves)
        for q in self.getFutureEvents().itervalues():
            timeLeftInfo = q.getNearestActivityTimeLeft()
            if timeLeftInfo is None:
                startTime = q.getStartTimeLeft()
            else:
                startTime = timeLeftInfo[0]
            invalidateTimeLeft = min(invalidateTimeLeft, startTime)

        if invalidateTimeLeft != sys.maxint:
            self.__loadInvalidateCallback(invalidateTimeLeft)
        self.__waitForSync = False
        self.onSyncCompleted()
        callback(True)
        from gui.shared import g_eventBus
        g_eventBus.handleEvent(events.LobbySimpleEvent(events.LobbySimpleEvent.EVENTS_UPDATED))
        return

    def __clearQuestsItemsCache(self):
        for qID, q in self._getQuests().iteritems():
            q.accountReqs.clearItemsCache()
            q.vehicleReqs.clearItemsCache()

    @classmethod
    def __getEventsData(cls, eventsTypeName):
        try:
            if isPlayerAccount():
                if eventsTypeName in BigWorld.player().eventsData:
                    return pickle.loads(zlib.decompress(BigWorld.player().eventsData[eventsTypeName]))
                return {}
            LOG_ERROR('Trying to get quests data from not account player', eventsTypeName, BigWorld.player())
        except Exception:
            LOG_CURRENT_EXCEPTION()

        return {}

    def __getQuestsData(self):
        return self.__getEventsData(EVENT_CLIENT_DATA.QUEST)

    def __getFortQuestsData(self):
        return self.__getEventsData(EVENT_CLIENT_DATA.FORT_QUEST)

    def __getPersonalQuestsData(self):
        return self.__getEventsData(EVENT_CLIENT_DATA.PERSONAL_QUEST)

    def __getActionsData(self):
        return self.__getEventsData(EVENT_CLIENT_DATA.ACTION)

    def __getEventBattles(self):
        return self.__getEventsData(EVENT_CLIENT_DATA.INGAME_EVENTS).get('eventBattles', {})

    def __getCompanyBattlesData(self):
        return self.__getEventsData(EVENT_CLIENT_DATA.INGAME_EVENTS).get('eventCompanies', {})

    def __getFallout(self):
        return self.__getEventsData(EVENT_CLIENT_DATA.FALLOUT)

    def __getCommonQuestsIterator(self):
        questsData = self.__getQuestsData()
        questsData.update(self.__getFortQuestsData())
        questsData.update(self.__getPersonalQuestsData())
        questsData.update(self.__getPotapovHiddenQuests())
        for qID, qData in questsData.iteritems():
            yield (qID, self._makeQuest(qID, qData))

        currentESportSeasonID = g_lobbyContext.getServerSettings().eSportCurrentSeason.getID()
        eSportQuests = clubs_quests.g_cache.getLadderQuestsBySeasonID(currentESportSeasonID) or []
        for questDescr in eSportQuests:
            yield (questDescr.questID, self._makeQuest(questDescr.questID, questDescr.questData, maker=_clubsQuestMaker, seasonID=currentESportSeasonID, questDescr=questDescr))

    def __loadInvalidateCallback(self, duration):
        LOG_DEBUG('load quest window invalidation callback (secs)', duration)
        self.__clearInvalidateCallback()
        self.__invalidateCbID = BigWorld.callback(math.ceil(duration), self.__invalidateData)

    def __clearInvalidateCallback(self):
        if self.__invalidateCbID is not None:
            BigWorld.cancelCallback(self.__invalidateCbID)
            self.__invalidateCbID = None
        return

    def __clearCache(self):
        self.__questsDossierBonuses.clear()
        self.__actionsCache.clear()
        for storage in self.__cache.itervalues():
            storage.clear()

    def __getPotapovHiddenQuests(self):
        if not self.__potapovHidden:
            xmlPath = _POTAPOV_QUEST_XML_PATH + '/tiles.xml'
            for quest in readQuestsFromFile(xmlPath, EVENT_TYPE.TOKEN_QUEST):
                self.__potapovHidden[quest[0]] = quest[3]

        return self.__potapovHidden.copy()
예제 #20
0
class EventListener(object):
    cursorType = property(lambda self: self.__cursorType)
    isBrowserPlayingAudio = False

    def __init__(self, browser):
        self.__cursorTypes = {
            CURSOR_TYPES.Hand: CursorManager.HAND,
            CURSOR_TYPES.Pointer: CursorManager.ARROW,
            CURSOR_TYPES.IBeam: CursorManager.IBEAM,
            CURSOR_TYPES.Grab: CursorManager.DRAG_OPEN,
            CURSOR_TYPES.Grabbing: CursorManager.DRAG_CLOSE,
            CURSOR_TYPES.ColumnResize: CursorManager.MOVE
        }
        self.__cursorType = None
        self.__eventMgr = EventManager()
        self.onLoadStart = Event(self.__eventMgr)
        self.onLoadEnd = Event(self.__eventMgr)
        self.onLoadingStateChange = Event(self.__eventMgr)
        self.onCursorUpdated = Event(self.__eventMgr)
        self.onDOMReady = Event(self.__eventMgr)
        self.onReady = Event(self.__eventMgr)
        self.onJsHostQuery = Event(self.__eventMgr)
        self.onTitleChange = Event(self.__eventMgr)
        self.onDestroy = Event(self.__eventMgr)
        self.onAudioStatusChanged = Event(self.__eventMgr)
        self.onConsoleMessage = Event(self.__eventMgr)
        self.__urlFailed = False
        self.__browserProxy = weakref.proxy(browser)
        return

    def clear(self):
        self.__eventMgr.clear()

    def newNavigation(self):
        self.__urlFailed = False

    def onChangeCursor(self, cursorType):
        self.__cursorType = self.__cursorTypes.get(
            cursorType) or CursorManager.ARROW
        self.onCursorUpdated()

    def onChangeTitle(self, title):
        _logger.debug('onChangeTitle %s', title)
        self.onTitleChange(title)

    def ready(self, success):
        self.onReady(success)

    def destroy(self):
        self.onDestroy()

    def onBeginLoadingFrame(self, frameId, isMainFrame, url):
        if isMainFrame:
            _logger.debug('onBeginLoadingFrame(isMainFrame) %s', url)
            self.onLoadStart(url)
            if self.__urlFailed:
                self.onLoadEnd(url, False)

    def onFailLoadingFrame(self, frameId, isMainFrame, url, errorCode,
                           errorDesc):
        if isMainFrame:
            _logger.debug(
                'onFailLoadingFrame(isMainFrame) %s, error: %r, text: %r', url,
                errorCode, errorDesc)
            self.__urlFailed = True
            self.onLoadEnd(url, not self.__urlFailed, errorDesc=errorDesc)

    def onFinishLoadingFrame(self, frameId, isMainFrame, url, httpStatusCode):
        if isMainFrame:
            _logger.debug(
                'onFinishLoadingFrame(isMainFrame) %s, httpStatusCode: %r',
                url, httpStatusCode)
            self.onLoadEnd(url, not self.__urlFailed, httpStatusCode)

    def onBrowserLoadingStateChange(self, isLoading):
        _logger.debug('onBrowserLoadingStateChange isLoading: %r', isLoading)
        self.onLoadingStateChange(isLoading)

    def onDocumentReady(self, url):
        _logger.debug('onDocumentReady %s', url)
        self.onDOMReady(url)

    def onAddConsoleMessage(self, level, message, lineNumber, source, viewId):
        self.onConsoleMessage(level, message, lineNumber, source, viewId)

    def onFilterNavigation(self, url):
        return self.__browserProxy.filterNavigation(url)

    def onResourceLoadRequest(self, method, url):
        _logger.debug('requested %s %s', method, url)
        return self.__browserProxy.onResourceLoadRequest(url)

    def onResourceLoadComplete(self, method, url):
        _logger.debug('completed %s %s', method, url)

    def onResourceLoadError(self, method, url):
        _logger.warn('failed %s %s', method, url)

    def onWhitelistMiss(self, isMainFrame, failedURL, httpStatusCode=None):
        if isMainFrame:
            self.onLoadStart(failedURL)
            self.onLoadEnd(failedURL, False, httpStatusCode)

    def onShowCreatedWebView(self, url, isPopup):
        _logger.debug('onShowCreatedWebView %s isPopup: %r', url, isPopup)
예제 #21
0
class EventListener():
    cursorType = property(lambda self: self.__cursorType)

    def __init__(self, browser):
        self.__cursorTypes = {
            CURSOR_TYPES.Hand: 'Cursor.HAND',
            CURSOR_TYPES.Pointer: 'Cursor.ARROW',
            CURSOR_TYPES.IBeam: 'Cursor.IBEAM',
            CURSOR_TYPES.Grab: 'Cursor.DRAG_OPEN',
            CURSOR_TYPES.Grabbing: 'Cursor.DRAG_CLOSE',
            CURSOR_TYPES.ColumnResize: 'Cursor.MOVE'
        }
        self.__cursorType = 'Cursor.ARROW'
        self.__eventMgr = EventManager()
        self.onLoadStart = Event(self.__eventMgr)
        self.onLoadEnd = Event(self.__eventMgr)
        self.onLoadingStateChange = Event(self.__eventMgr)
        self.onCursorUpdated = Event(self.__eventMgr)
        self.onDOMReady = Event(self.__eventMgr)
        self.onReady = Event(self.__eventMgr)
        self.onJsHostQuery = Event(self.__eventMgr)
        self.onTitleChange = Event(self.__eventMgr)
        self.__urlFailed = False
        self.__browserProxy = weakref.proxy(browser)

    def clear(self):
        self.__eventMgr.clear()

    def newNavigation(self):
        self.__urlFailed = False

    def onChangeCursor(self, cursorType):
        self.__cursorType = self.__cursorTypes.get(
            cursorType) or 'Cursor.ARROW'
        self.onCursorUpdated()

    def onChangeTitle(self, title):
        LOG_BROWSER('onChangeTitle "{}"'.format(title))
        self.onTitleChange(title)

    def ready(self, success):
        self.onReady(success)

    def onBeginLoadingFrame(self, frameId, isMainFrame, url):
        if isMainFrame:
            LOG_BROWSER('onBeginLoadingFrame(isMainFrame) "{}"'.format(url))
            self.onLoadStart(url)
            if self.__urlFailed:
                self.onLoadEnd(url, False)

    def onFailLoadingFrame(self, frameId, isMainFrame, url, errorCode,
                           errorDesc):
        if isMainFrame:
            LOG_BROWSER(
                'onFailLoadingFrame(isMainFrame) "{}", errorCode:{}, errorDesc:{}'
                .format(url, errorCode, errorDesc))
            self.__urlFailed = True

    def onFinishLoadingFrame(self, frameId, isMainFrame, url, httpStatusCode):
        if isMainFrame:
            LOG_BROWSER(
                'onFinishLoadingFrame(isMainFrame) "{}" status:{}'.format(
                    url, httpStatusCode))
            self.onLoadEnd(url, not self.__urlFailed, httpStatusCode)

    def onBrowserLoadingStateChange(self, isLoading):
        LOG_BROWSER(
            'onBrowserLoadingStateChange() isLoading:{}'.format(isLoading))
        self.onLoadingStateChange(isLoading)

    def onDocumentReady(self, url):
        LOG_BROWSER('onDocumentReady "{}"'.format(url))
        self.onDOMReady(url)

    def onAddConsoleMessage(self, message, lineNumber, source):
        pass

    def onFilterNavigation(self, url):
        """
        This event occurs before frame navigations. You can use this to
        block or log navigations for each frame of a WebView.
        
        :param url: The URL that the frame wants to navigate to.
        :return: True to block a navigation. Return False to let it continue.
        """
        return self.__browserProxy.filterNavigation(url)

    def onWhitelistMiss(self, isMainFrame, failedURL):
        if isMainFrame:
            LOG_BROWSER('onWhitelistMiss(isMainFrame) "{}"'.format(failedURL))
            self.onLoadStart(failedURL)
            self.onLoadEnd(failedURL, False)

    def onShowCreatedWebView(self, url, isPopup):
        LOG_BROWSER('onShowCreatedWebView "{}" isPopup:{}'.format(
            url, isPopup))
예제 #22
0
class WebBrowserImpl(object):
    _WOWP_CLIENT_PARAM_NAME = 'wowp_client_param'
    url = property(lambda self:
                   ('' if self.__browser is None else self.__browser.url))
    isFocused = property(lambda self: self.__isFocused)
    hasBrowser = property(lambda self: self.__browser is not None)
    isSuccessfulLoad = property(lambda self: self.__successfulLoad)
    skipEscape = property(lambda self: self.__skipEscape)
    ignoreKeyEvents = property(lambda self: self.__ignoreKeyEvents)
    useSpecialKeys = property(lambda self: self.__useSpecialKeys)
    allowMouseWheel = property(lambda self: self.__allowMouseWheel)

    @skipEscape.setter
    def skipEscape(self, value):
        LOG_BROWSER('skipEscape set %s (was: %s)' % (value, self.__skipEscape))
        self.__skipEscape = value

    @ignoreKeyEvents.setter
    def ignoreKeyEvents(self, value):
        LOG_BROWSER('ignoreKeyEvents set %s (was: %s)' %
                    (value, self.__ignoreKeyEvents))
        self.__ignoreKeyEvents = value

    @useSpecialKeys.setter
    def useSpecialKeys(self, value):
        LOG_BROWSER('useSpecialKeys set %s (was: %s)' %
                    (value, self.__useSpecialKeys))
        self.__useSpecialKeys = value

    @allowMouseWheel.setter
    def allowMouseWheel(self, value):
        LOG_BROWSER('allowMouseWheel set %s (was: %s)' %
                    (value, self.__allowMouseWheel))
        self.__allowMouseWheel = value

    def __init__(self, browser_id, width, height, sfMovieClip, sfResourceName,
                 url):
        self.__width = width
        self.__height = height
        self.__sfMovieClip = weakref.ref(sfMovieClip)
        self.__sfResourceName = sfResourceName
        self.__browserId = browser_id
        self.__browser = None
        self.__isFocused = False
        self.__isReady = False
        self.__baseUrl = url
        self.__navigationFilters = set()
        self.__skipEscape = True
        self.__ignoreKeyEvents = False
        self.__useSpecialKeys = True
        self.__allowMouseWheel = True
        self.__disableKeyHandlers = []
        self.__loadStartTime = BigWorld.time()
        self.__enableUpdate = False
        self.__isMouseDown = False
        self.__isWaitingForUnfocus = False
        self.__allowAutoLoadingScreenChange = True
        self.__isNavigationComplete = False
        self.__successfulLoad = False
        self.__delayedUrls = []
        self.__isCloseTriggered = False
        self.__specialKeyHandlers = None
        self.__browserKeyHandlers = None
        self.__eventMgr = EventManager()
        self.onLoadStart = Event(self.__eventMgr)
        self.onLoadEnd = Event(self.__eventMgr)
        self.onLoadingStateChange = Event(self.__eventMgr)
        self.onReadyToShowContent = Event(self.__eventMgr)
        self.onNavigate = Event(self.__eventMgr)
        self.onReady = Event(self.__eventMgr)
        self.onJsHostQuery = Event(self.__eventMgr)
        self.onTitleChange = Event(self.__eventMgr)
        self.onFailedCreation = Event(self.__eventMgr)
        self.onCanCreateNewBrowser = Event(self.__eventMgr)
        self.onCursorUpdated = Event(self.__eventMgr)
        return

    def create(self):
        LOG_BROWSER('Create id:{}'.format(self.__browserId))
        clientLanguage = ''
        self.__browser = BigWorld.createBrowser(self.__browserId,
                                                clientLanguage)
        if self.__browser is None:
            LOG_BROWSER('create() NO BROWSER WAS CREATED')
            return False
        else:
            self.__browser.script = EventListener(self)
            self.__browser.script.onLoadStart += self.__onLoadStart
            self.__browser.script.onLoadEnd += self.__onLoadEnd
            self.__browser.script.onLoadingStateChange += self.__onLoadingStateChange
            self.__browser.script.onDOMReady += self.__onReadyToShowContent
            self.__browser.script.onCursorUpdated += self.__onCursorUpdated
            self.__browser.script.onReady += self.__onReady
            self.__browser.script.onJsHostQuery += self.__onJsHostQuery
            self.__browser.script.onTitleChange += self.__onTitleChange

            def injectBrowserKeyEvent(me, e):
                if _BROWSER_KEY_LOGGING:
                    LOG_BROWSER(
                        'injectBrowserKeyEvent key:{} isKeyDown:{} isAltDown:{} isShiftDown:{} isCtrlDown:{}'
                        .format(e.key, e.isKeyDown(), e.isAltDown(),
                                e.isShiftDown(), e.isCtrlDown()))
                me.__browser.injectKeyEvent(e)

            def injectKeyDown(me, e):
                injectBrowserKeyEvent(me, e)

            def injectKeyUp(me, e):
                injectBrowserKeyEvent(me, e)

            def resetBit(value, bitMask):
                return value & ~bitMask

            self.__specialKeyHandlers = (
                (Keys.KEY_LEFTARROW, True, True, None, None,
                 lambda me, _: me.__browser.goBack()),
                (Keys.KEY_RIGHTARROW, True, True, None, None,
                 lambda me, _: me.__browser.goForward()),
                (Keys.KEY_F5, True, None, None, None,
                 lambda me, _: me.__browser.reload()))
            self.__browserKeyHandlers = (
                (Keys.KEY_LSHIFT, False, None, True, None,
                 lambda me, e: injectKeyUp(
                     me,
                     BigWorld.KeyEvent(e.key, e.repeatCount,
                                       resetBit(e.modifiers, 1), None, e.
                                       cursorPosition, 0))),
                (Keys.KEY_RSHIFT, False, None, True, None,
                 lambda me, e: injectKeyUp(
                     me,
                     BigWorld.KeyEvent(e.key, e.repeatCount,
                                       resetBit(e.modifiers, 1), None, e.
                                       cursorPosition, 0))),
                (Keys.KEY_LCONTROL, False, None, None, True,
                 lambda me, e: injectKeyUp(
                     me,
                     BigWorld.KeyEvent(e.key, e.repeatCount,
                                       resetBit(e.modifiers, 2), None, e.
                                       cursorPosition, 0))),
                (Keys.KEY_RCONTROL, False, None, None, True,
                 lambda me, e: injectKeyUp(
                     me,
                     BigWorld.KeyEvent(e.key, e.repeatCount,
                                       resetBit(e.modifiers, 2), None, e.
                                       cursorPosition, 0))),
                (None, True, None, None, None,
                 lambda me, e: injectKeyDown(me, e)),
                (None, False, None, None, None,
                 lambda me, e: injectKeyUp(me, e)))
            self.__disableKeyHandlers = []
            return True

    def setDisabledKeys(self, keys):
        self.__disableKeyHandlers = []
        for key, isKeyDown, isAltDown, isShiftDown, isCtrlDown in keys:
            self.__disableKeyHandlers.append(
                (key, isKeyDown, isAltDown, isShiftDown, isCtrlDown,
                 lambda me, e: None))

    def ready(self, success):
        LOG_BROWSER('ready: id:{}, status:{}'.format(
            self.__browserId, 'success' if success else ''))
        self.__successfulLoad = False
        self.__enableUpdate = True
        self.__isMouseDown = False
        self.__isFocused = False
        self.__isWaitingForUnfocus = False
        if success:
            if self.__sfMovieClip():
                self.__browser.setScaleformRender(self.__sfMovieClip(),
                                                  self.__sfResourceName,
                                                  self.__width, self.__height)
            self.__browser.activate(True)
            self.__browser.loadURL(self.__baseUrl)
            self.__isReady = True
            self.focus(True)
            self.onReady(self.__browser.url, success)
        else:
            self.__isNavigationComplete = True
            self.onFailedCreation(self.__baseUrl)

    def __processDelayedNavigation(self):
        if self.__isNavigationComplete and self.__delayedUrls:
            self.doNavigate(self.__delayedUrls.pop(0))
            return True
        return False

    def destroy(self):
        LOG_BROWSER('fini id:{}'.format(self.__browserId))
        self.__eventMgr.clear()
        self.__eventMgr = None
        if self.__browser is not None:
            self.__browser.script.clear()
            self.__browser.script = None
            if self.__sfMovieClip():
                self.__browser.resetScaleformRender(self.__sfMovieClip(),
                                                    self.__sfResourceName)
            BigWorld.removeBrowser(self.__browserId)
            self.__browser = None
        self.__navigationFilters = None
        self.onCursorUpdated('Cursor.ARROW')
        return

    def focus(self, focus):
        if self.hasBrowser:
            if focus and not self.__isFocused:
                self.__browser.focus()
                self.__isFocused = True
                self.onCursorUpdated(self.__browser.script.cursorType)
            elif not focus and self.__isFocused:
                self.__browser.unfocus()
                self.__isFocused = False
                self.__isWaitingForUnfocus = False

    def refresh(self, ignoreCache=True):
        if BigWorld.time() - self.__loadStartTime < 0.5:
            LOG_BROWSER('refresh - called too soon')
            return
        if self.hasBrowser:
            self.__browser.reload()
            self.onNavigate(self.__browser.url)

    def navigate(self, url):
        lastIsSame = self.__delayedUrls and self.__delayedUrls[-1] == url
        if not lastIsSame:
            self.__delayedUrls.append(url)
        self.__processDelayedNavigation()

    def sendMessage(self, message):
        if self.hasBrowser:
            self.__browser.sendMessage(message)

    def doNavigate(self, url):
        LOG_BROWSER('doNavigate: {}'.format(url))
        self.__baseUrl = url
        if self.hasBrowser:
            self.__browser.script.newNavigation()
            self.__browser.loadURL(url)
            self.onNavigate(url)

    def navigateBack(self):
        if self.hasBrowser:
            self.__browser.goBack(self.url)

    def navigateForward(self):
        if self.hasBrowser:
            self.__browser.goForward(self.url)

    def navigateStop(self):
        if BigWorld.time() - self.__loadStartTime < 0.5:
            LOG_BROWSER('navigateStop - called too soon')
            return
        if self.hasBrowser:
            self.__browser.stop()
            self.__onLoadEnd(self.__browser.url)

    def __getBrowserKeyHandler(self, key, isKeyDown, isAltDown, isShiftDown,
                               isCtrlDown):
        from itertools import izip
        params = (key, isKeyDown, isAltDown, isShiftDown, isCtrlDown)
        matches = lambda t: t[0] is None or t[0] == t[1]
        browserKeyHandlers = tuple(
            self.__disableKeyHandlers) + self.__browserKeyHandlers
        if self.useSpecialKeys:
            browserKeyHandlers = self.__specialKeyHandlers + browserKeyHandlers
        for values in browserKeyHandlers:
            if reduce(lambda a, b: a and matches(b), izip(values, params),
                      True):
                return values[-1]

        return None

    def handleKeyEvent(self, event):
        if not (self.hasBrowser and self.__enableUpdate):
            return False
        e = event
        keyState = (e.key, e.isKeyDown(), e.isAltDown(), e.isShiftDown(),
                    e.isCtrlDown())
        if not self.skipEscape and e.key == Keys.KEY_ESCAPE and e.isKeyDown():
            self.__getBrowserKeyHandler(*keyState)(self, e)
            return True
        if not self.isFocused:
            self.__browser.injectKeyModifiers(e)
            return False
        if _BROWSER_KEY_LOGGING:
            LOG_BROWSER('handleKeyEvent {}'.format(keyState))
        if self.ignoreKeyEvents:
            return False
        if e.key in (Keys.KEY_ESCAPE, Keys.KEY_SYSRQ, Keys.KEY_LEFTMOUSE,
                     Keys.KEY_RIGHTMOUSE):
            return False
        if e.key in (Keys.KEY_RETURN, Keys.KEY_NUMPADENTER) and e.isAltDown():
            return False
        self.__getBrowserKeyHandler(*keyState)(self, e)
        return True

    def browserMove(self, x, y, z):
        if not (self.hasBrowser and self.__enableUpdate and self.isFocused):
            return
        if z != 0:
            if self.allowMouseWheel:
                self.__browser.injectMouseWheelEvent(z * 20)
            return
        self.__browser.injectMouseMoveEvent(x, y)

    def browserDown(self, x, y, z):
        if not (self.hasBrowser and self.__enableUpdate):
            return
        elif self.__isMouseDown:
            return
        else:
            if not self.isFocused:
                self.focus(True)
                self.__isMouseDown = True
                self.browserUp(x, y, z)
                self.browserMove(x, y, z)
            self.__isMouseDown = True
            self.__browser.injectKeyEvent(
                BigWorld.KeyEvent(Keys.KEY_LEFTMOUSE, 0, 0, None, (x, y), 0))
            return

    def browserUp(self, x, y, z):
        if not (self.hasBrowser and self.__enableUpdate):
            return
        elif not self.__isMouseDown:
            return
        else:
            self.__isMouseDown = False
            self.__browser.injectKeyEvent(
                BigWorld.KeyEvent(Keys.KEY_LEFTMOUSE, -1, 0, None, (x, y), 0))
            if self.__isWaitingForUnfocus:
                self.focus(False)
            return

    def browserFocusOut(self):
        if self.isFocused and self.__isMouseDown:
            self.__isWaitingForUnfocus = True
            return
        self.focus(False)

    def browserAction(self, action):
        if self.hasBrowser and self.__enableUpdate:
            if action == 'reload' and self.__isNavigationComplete:
                self.refresh()
            elif action == 'loading' and not self.__isNavigationComplete:
                self.navigateStop()

    def onBrowserShow(self, needRefresh):
        self.__enableUpdate = True
        if needRefresh and self.__baseUrl != self.url:
            self.navigate(self.url)
        self.focus(True)

    def onBrowserHide(self):
        self.navigate(self.__baseUrl)
        self.__enableUpdate = False
        self.focus(False)

    def addFilter(self, handler):
        if handler in self.__navigationFilters:
            LOG_ERROR_BROWSER(
                'Navigation filter is already added {}'.format(handler))
        else:
            self.__navigationFilters.add(handler)

    def removeFilter(self, handler):
        if handler in self.__navigationFilters:
            self.__navigationFilters.discard(handler)
        else:
            LOG_ERROR_BROWSER(
                "Trying to delete navigation filter which doesn't exist {}".
                format(handler))

    def filterNavigation(self, url):
        query = urlparse.urlparse(url).query
        tags = urlparse.parse_qs(query).get(self._WOWP_CLIENT_PARAM_NAME, [])
        stopNavigation = False
        closeBrowser = False
        for handler in self.__navigationFilters:
            try:
                result = handler(url, tags)
                stopNavigation |= result.stopNavigation
                closeBrowser |= result.closeBrowser
                if result.stopNavigation:
                    LOG_BROWSER(
                        'Navigation filter triggered navigation stop: {}'.
                        format(handler))
                if result.closeBrowser:
                    LOG_BROWSER(
                        'Navigation filter triggered browser close: {}'.format(
                            handler))
            except:
                LOG_CURRENT_EXCEPTION()

        self.__isCloseTriggered = closeBrowser
        return stopNavigation

    def setLoadingScreenVisible(self, visible):
        LOG_BROWSER('setLoadingScreenVisible {}'.format(visible))
        self.onLoadingStateChange(visible, True)

    def setAllowAutoLoadingScreen(self, enabled):
        LOG_BROWSER('setAllowAutoLoadingScreen {}'.format(enabled))
        self.__allowAutoLoadingScreenChange = enabled

    def changeTitle(self, title):
        self.onTitleChange(title)

    def __onLoadStart(self, url):
        if url == self.__browser.url:
            self.__isNavigationComplete = False
            self.__loadStartTime = BigWorld.time()
            LOG_BROWSER('onLoadStart {}'.format(self.__browser.url))
            self.onLoadStart(self.__browser.url)
            self.__successfulLoad = False

    def __onLoadEnd(self, url, isLoaded=True, httpStatusCode=None):
        if url == self.__browser.url:
            self.__isNavigationComplete = True
            self.__successfulLoad = isLoaded
            if not self.__processDelayedNavigation():
                LOG_BROWSER('onLoadEnd {} {} {}'.format(
                    self.__browser.url, isLoaded, httpStatusCode))
                self.onLoadEnd(self.__browser.url, isLoaded, httpStatusCode)

    def __onLoadingStateChange(self, isLoading):
        LOG_BROWSER('onLoadingStateChange {} {}'.format(
            isLoading, self.__allowAutoLoadingScreenChange))
        self.onLoadingStateChange(isLoading,
                                  self.__allowAutoLoadingScreenChange)
        if self.__isCloseTriggered:
            pass
        elif not isLoading:
            self.onCanCreateNewBrowser()

    def __onReadyToShowContent(self, url):
        if url == self.__browser.url:
            LOG_BROWSER('onReadyToShowContent {}'.format(self.__browser.url))
            self.onReadyToShowContent(self.__browser.url)

    def __isValidTitle(self, title):
        if self.__browser.url.startswith('about:'):
            return False
        if self.__browser.url.endswith(title):
            return False
        if self.__browser.url.endswith('/'):
            secondtest = self.__browser.url[:-1]
            if secondtest.endswith(title):
                return False
        if self.__baseUrl == title or self.__baseUrl.endswith(title):
            return False
        return True

    def __onTitleChange(self, title):
        if self.hasBrowser and self.__isValidTitle(title):
            LOG_BROWSER('onTitleChange {} {}'.format(title,
                                                     self.__browser.url))
            self.onTitleChange(title)

    def __onCursorUpdated(self):
        if self.hasBrowser and self.isFocused:
            self.onCursorUpdated(self.__browser.script.cursorType)

    def __onReady(self, success):
        self.ready(success)

    def __onJsHostQuery(self, command):
        self.onJsHostQuery(command)

    def executeJavascript(self, script, frame):
        if self.hasBrowser:
            self.__browser.executeJavascript(script, frame)
예제 #23
0
class BuyBoosterMeta(I18nConfirmDialogMeta):

    def __init__(self, boosterID, balance):
        super(BuyBoosterMeta, self).__init__('buyConfirmation', scope=ScopeTemplates.LOBBY_SUB_SCOPE)
        self.__booster = g_goodiesCache.getBooster(boosterID)
        self.__balance = balance
        self._eManager = EventManager()
        self.onInvalidate = Event(self._eManager)
        g_clientUpdateManager.addCallbacks({'stats': self.__onStatsChanged})

    def getEventType(self):
        return events.ShowDialogEvent.SHOW_CONFIRM_BOOSTER

    def getBoosterID(self):
        return self.__booster.boosterID

    def getBooster(self):
        return self.__booster

    def destroy(self):
        self.__booster = None
        self.__balance = None
        self._eManager.clear()
        g_clientUpdateManager.removeObjectCallbacks(self)
        return

    def getMaxAvailableItemsCount(self):
        return (self.__getMaxCount(Currency.CREDITS), self.__getMaxCount(Currency.GOLD))

    def getActionVO(self):
        buyPrice = self.__booster.buyPrice
        defaultPrice = self.__booster.defaultPrice
        if buyPrice != defaultPrice:
            return packActionTooltipData(ACTION_TOOLTIPS_TYPE.BOOSTER, str(self.__booster.boosterID), True, buyPrice, defaultPrice)
        else:
            return None

    def getCurrency(self):
        return self.__booster.getBuyPriceCurrency()

    def getPrice(self):
        return self.__booster.buyPrice

    @process('buyItem')
    def submit(self, count, currency):
        result = yield BoosterBuyer(self.__booster, count, currency == Currency.GOLD).request()
        if len(result.userMsg):
            SystemMessages.g_instance.pushI18nMessage(result.userMsg, type=result.sysMsgType)

    def __onStatsChanged(self, stats):
        if 'credits' in stats:
            self.__balance = self.__balance.replace(Currency.CREDITS, stats['credits'])
            self.onInvalidate()
        if 'gold' in stats:
            self.__balance = self.__balance.replace(Currency.GOLD, stats['gold'])
            self.onInvalidate()

    def __getMaxCount(self, currency):
        result = 0
        boosterPrice = self.__booster.buyPrice
        if boosterPrice.get(currency) > 0:
            result = math.floor(self.__balance.get(currency) / boosterPrice.get(currency))
        return min(result, MAX_BOOSTERS_FOR_OPERATION)
예제 #24
0
class _PreDefinedHostList(object):

    def __init__(self):
        super(_PreDefinedHostList, self).__init__()
        self._eManager = EventManager()
        self.onCsisQueryStart = Event(self._eManager)
        self.onCsisQueryComplete = Event(self._eManager)
        self.onPingPerformed = Event(self._eManager)
        self._hosts = []
        self._urlMap = {}
        self._nameMap = {}
        self._peripheryMap = {}
        self._isDataLoaded = False
        self._isCSISQueryInProgress = False
        self.__csisUrl = ''
        self.__csisResponse = {}
        self.__lastRoamingHosts = []
        self.__csisCallbackID = None
        self.__lastCsisUpdateTime = 0
        self.__queryCallback = None
        self.__autoLoginQueryState = AUTO_LOGIN_QUERY_STATE.DEFAULT
        self.__csisAction = CSIS_ACTION.DEFAULT
        self.__recommended = []
        self.__pingRequester = _PingRequester(self.__onPingPerformed)
        return

    def fini(self):
        self._hosts = []
        self._urlMap.clear()
        self._nameMap.clear()
        self._peripheryMap.clear()
        self._isDataLoaded = False
        self.__csisResponse.clear()
        self.__csisUrl = ''
        self.__lastCsisUpdateTime = None
        self.__queryCallback = None
        self.__autoLoginQueryState = AUTO_LOGIN_QUERY_STATE.DEFAULT
        self.__csisAction = CSIS_ACTION.DEFAULT
        self._eManager.clear()
        self.__pingRequester.fini()
        self.__cleanCsisTimerCallback()
        return

    @property
    def lastRoamingHosts(self):
        return self.__lastRoamingHosts

    def startCSISUpdate(self):
        if len(self.hosts()) > 1:
            self.__csisAction = CSIS_ACTION.addIfNot(self.__csisAction, CSIS_ACTION.UPDATE_ON_TIME)
            self.__sendCsisQuery()

    def stopCSISUpdate(self):
        self.__csisAction = CSIS_ACTION.removeIfHas(self.__csisAction, CSIS_ACTION.UPDATE_ON_TIME)
        self.__cleanCsisTimerCallback()

    def requestPing(self, forced=False):
        self.__pingRequester.request(self._hosts, forced)

    def getPingResult(self):
        return self.__pingRequester.result()

    def getHostPingData(self, host):
        return self.getPingResult().get(host, _DEFAULT_PING_DATA)

    def autoLoginQuery(self, callback):
        if callback is None:
            LOG_WARNING('Callback is not defined.')
            return
        elif self.__autoLoginQueryState != AUTO_LOGIN_QUERY_STATE.DEFAULT:
            LOG_WARNING('Auto login query in process. Current state: {}'.format(self.__autoLoginQueryState))
            return
        elif len(self._hosts) < 2:
            callback(self.first())
            return
        elif self.__recommended:
            LOG_DEBUG('Gets recommended from previous query', self.__recommended)
            host = self.__choiceFromRecommended()
            LOG_DEBUG('Recommended host', host)
            callback(host)
            return
        else:
            self.__autoLoginQueryState = AUTO_LOGIN_QUERY_STATE.START
            self.__queryCallback = callback
            self.__pingRequester.request(self.peripheries())
            self.__csisAction = CSIS_ACTION.addIfNot(self.__csisAction, CSIS_ACTION.AUTO_LOGIN_REQUEST)
            self.__sendCsisQuery()
            return

    def resetQueryResult(self):
        self.__recommended = []
        self.__pingRequester.clear()

    def readScriptConfig(self, dataSection, userDataSection=None):
        if self._isDataLoaded or dataSection is None:
            return
        else:

            def _readSvrList(section, nodeName):
                return section[nodeName].items() if section is not None and section.has_key(nodeName) else []

            self.__csisUrl = dataSection.readString('csisUrl')
            self._hosts = []
            self._urlMap.clear()
            self._nameMap.clear()
            self._peripheryMap.clear()
            svrList = _readSvrList(dataSection, 'login') + _readSvrList(userDataSection, 'development/login')
            for name, subSec in svrList:
                name = subSec.readString('name')
                shortName = subSec.readString('short_name')
                urls = _LoginAppUrlIterator(subSec.readStrings('url'))
                host = urls.primary
                if host is not None:
                    if not name:
                        name = host
                    keyPath = subSec.readString('public_key_path')
                    if not keyPath:
                        keyPath = None
                    areaID = subSec.readString('game_area_id')
                    if not areaID:
                        areaID = None
                    app = self._makeHostItem(name, shortName, host, urlToken=subSec.readString('url_token'), urlIterator=urls if len(urls) > 1 else None, keyPath=keyPath, areaID=areaID, peripheryID=subSec.readInt('periphery_id', 0))
                    idx = len(self._hosts)
                    url = app.url
                    if url in self._urlMap:
                        LOG_WARNING('Host url is already added. This host is ignored', url)
                        continue
                    self._urlMap[url] = idx
                    urlToken = app.urlToken
                    if urlToken:
                        if urlToken in self._urlMap:
                            LOG_WARNING('Alternative host url is already added. This url is ignored', app.url)
                        else:
                            self._urlMap[urlToken] = idx
                    self._nameMap[app.name] = idx
                    self._peripheryMap[app.peripheryID] = idx
                    self._hosts.append(app)

            self._isDataLoaded = True
            return

    def predefined(self, url):
        return url in self._urlMap

    def roaming(self, url):
        return url in [ p.url for p in self.roamingHosts() ]

    def first(self):
        return self._hosts[0] if self._hosts else self._makeHostItem('', '', '')

    def byUrl(self, url):
        result = self._makeHostItem('', '', url)
        index = self._urlMap.get(url, -1)
        if index > -1:
            result = self._hosts[index]
        else:
            for host in self.roamingHosts():
                if host.url == url:
                    result = host

        return result

    def byName(self, name):
        result = self._makeHostItem(name, '', '')
        index = self._nameMap.get(name, -1)
        if index > -1:
            result = self._hosts[index]
        else:
            for host in self.roamingHosts():
                if host.name == name:
                    result = host

        return result

    def hosts(self):
        return self._hosts[:]

    def shortList(self):
        result = self.getSimpleHostsList(self._hosts)
        if AUTO_LOGIN_QUERY_ENABLED and len(result) > 1 and len(self.peripheries()) > 1:
            result.insert(0, (AUTO_LOGIN_QUERY_URL,
             i18n.makeString('#menu:login/auto'),
             HOST_AVAILABILITY.IGNORED,
             None))
        return result

    def getSimpleHostsList(self, hosts, withShortName=False):
        result = []
        defAvail = self.getDefaultCSISStatus()
        predefined = tuple((host.url for host in self.peripheries()))
        isInProgress = self._isCSISQueryInProgress
        csisResGetter = self.__csisResponse.get
        for item in hosts:
            if item.url not in predefined:
                status = HOST_AVAILABILITY.IGNORED
            else:
                status = defAvail if isInProgress else csisResGetter(item.peripheryID, defAvail)
            if withShortName:
                result.append((item.url,
                 item.name,
                 item.shortName,
                 status,
                 item.peripheryID))
            result.append((item.url,
             item.name,
             status,
             item.peripheryID))

        return result

    def getDefaultCSISStatus(self):
        from gui import GUI_SETTINGS
        if not self.__csisUrl:
            defAvail = HOST_AVAILABILITY.IGNORED
        elif GUI_SETTINGS.csisRequestRate == REQUEST_RATE.NEVER:
            defAvail = HOST_AVAILABILITY.IGNORED
        elif len(g_preDefinedHosts.hosts()) > 1:
            defAvail = HOST_AVAILABILITY.REQUESTED
        else:
            defAvail = HOST_AVAILABILITY.IGNORED
        return defAvail

    def urlIterator(self, primary):
        result = None
        index = self._urlMap.get(primary, -1)
        if index > -1:
            result = self._hosts[index].urlIterator
        return result

    def periphery(self, peripheryID, useRoaming=True):
        if peripheryID in self._peripheryMap:
            index = self._peripheryMap[peripheryID]
            return self._hosts[index]
        else:
            if useRoaming:
                roamingHosts = dict(((host.peripheryID, host) for host in self.roamingHosts()))
                if peripheryID in roamingHosts:
                    return roamingHosts[peripheryID]
            return None

    def peripheries(self):
        return [ app for app in self._hosts if app.peripheryID ]

    def roamingHosts(self):
        p = BigWorld.player()
        result = []
        if hasattr(p, 'serverSettings'):
            for peripheryID, name, shortName, host, keyPath in p.serverSettings['roaming'][3]:
                result.append(self._makeHostItem(name, shortName, host, keyPath=keyPath, peripheryID=peripheryID))

            self.__lastRoamingHosts = sorted(result, key=operator.itemgetter(0))
        return self.__lastRoamingHosts

    def hostsWithRoaming(self):
        predefined = tuple((host.url for host in self.peripheries()))
        hosts = self.peripheries()
        for h in self.roamingHosts():
            if h.url not in predefined:
                hosts.append(h)

        return hosts

    def isRoamingPeriphery(self, peripheryID):
        return peripheryID not in [ p.peripheryID for p in self.peripheries() ]

    def _makeHostItem(self, name, shortName, url, urlToken='', urlIterator=None, keyPath=None, areaID=None, peripheryID=0):
        if not shortName:
            shortName = name
        return _HostItem(name, shortName, url, urlToken, urlIterator, keyPath, areaID, peripheryID)

    def _determineRecommendHost(self):
        defAvail = HOST_AVAILABILITY.NOT_AVAILABLE
        csisResGetter = self.__csisResponse.get
        queryResult = [ (host, self.getHostPingData(host.url).value, csisResGetter(host.peripheryID, defAvail)) for host in self.peripheries() ]
        self.__recommended = [ item for item in queryResult if item[2] == HOST_AVAILABILITY.RECOMMENDED ]
        if not self.__recommended:
            self.__recommended = [ item for item in queryResult if item[2] == HOST_AVAILABILITY.NOT_RECOMMENDED ]
        recommendLen = len(self.__recommended)
        if not recommendLen:
            if len(queryResult) > 1:
                LOG_DEBUG('List of recommended is empty. Gets host by ping')
                self.__recommended = self.__filterRecommendedByPing(queryResult)
                LOG_DEBUG('Recommended by ping', self.__recommended)
                result = self.__choiceFromRecommended()
            else:
                LOG_DEBUG('Gets first as recommended')
                result = self.first()
        else:
            LOG_DEBUG('Recommended by CSIS', self.__recommended)
            if recommendLen > 1:
                self.__recommended = self.__filterRecommendedByPing(self.__recommended)
                LOG_DEBUG('Recommended by ping', self.__recommended)
            result = self.__choiceFromRecommended()
        return result

    def __startCsisTimer(self):
        self.__cleanCsisTimerCallback()
        self.__csisCallbackID = BigWorld.callback(CSIS_REQUEST_TIMER, self.__onCsisTimer)

    def __cleanCsisTimerCallback(self):
        if self.__csisCallbackID:
            BigWorld.cancelCallback(self.__csisCallbackID)
            self.__csisCallbackID = None
        return

    def __onCsisTimer(self):
        self.__csisCallbackID = None
        self.__sendCsisQuery()
        return

    def __sendCsisQuery(self):
        isReplay = _isReplay('CSIS')
        if not isReplay and self.__csisUrl:
            if not self._isCSISQueryInProgress:
                timeFromLastUpdate = time.time() - self.__lastCsisUpdateTime
                if timeFromLastUpdate >= CSIS_REQUEST_TIMER:
                    self._isCSISQueryInProgress = True
                    self.onCsisQueryStart()
                    allHosts = self.hosts()
                    peripheries = [ host.peripheryID for host in allHosts if host.peripheryID ]
                    LOG_DEBUG('CSIS query sending', peripheries)
                    worker = _getCSISWorker(self.__csisUrl, self.__receiveCsisResponse, peripheries)
                    worker.start()
                else:
                    self.__finishCsisQuery()
        else:
            if not isReplay:
                LOG_DEBUG('CSIS url is not defined - ignore')
            self._isCSISQueryInProgress = False
            self.stopCSISUpdate()
            self.__finishCsisQuery()
            self.__lastCsisUpdateTime = 0

    def __receiveCsisResponse(self, response):
        LOG_DEBUG('CSIS query received', response)
        self._isCSISQueryInProgress = False
        self.__csisResponse = response
        self.__lastCsisUpdateTime = time.time()
        self.__finishCsisQuery()

    def __finishCsisQuery(self):
        if self.__csisAction & CSIS_ACTION.AUTO_LOGIN_REQUEST:
            self.__receiveAutoLoginCSISResponse(self.__csisResponse)
        if self.__csisAction & CSIS_ACTION.UPDATE_ON_TIME:
            self.__startCsisTimer()
        self.onCsisQueryComplete(self.__csisResponse)

    def __onPingPerformed(self, result):
        self.onPingPerformed(result)
        if self.__autoLoginQueryState & AUTO_LOGIN_QUERY_STATE.START:
            self.__autoLoginQueryCompleted(AUTO_LOGIN_QUERY_STATE.PING_PERFORMED)

    def __receiveAutoLoginCSISResponse(self, response):
        self.__csisAction = CSIS_ACTION.removeIfHas(self.__csisAction, CSIS_ACTION.AUTO_LOGIN_REQUEST)
        self.__autoLoginQueryCompleted(AUTO_LOGIN_QUERY_STATE.CSIS_RESPONSE_RECEIVED)

    def __autoLoginQueryCompleted(self, state):
        if not self.__autoLoginQueryState & state:
            self.__autoLoginQueryState |= state
        if self.__autoLoginQueryState == AUTO_LOGIN_QUERY_STATE.COMPLETED:
            host = self._determineRecommendHost()
            LOG_DEBUG('Recommended host', host)
            self.__autoLoginQueryState = AUTO_LOGIN_QUERY_STATE.DEFAULT
            self.__queryCallback(host)
            self.__queryCallback = None
        return

    def __filterRecommendedByPing(self, recommended):
        result = recommended
        filtered = [ item for item in recommended if item[1] > UNDEFINED_PING_VAL ]
        if filtered:
            minPingTime = min(filtered, key=lambda item: item[1])[1]
            maxPingTime = 1.2 * minPingTime
            result = [ item for item in filtered if item[1] < maxPingTime ]
        return result

    def __choiceFromRecommended(self):
        recommended = random.choice(self.__recommended)
        self.__recommended = [ item for item in self.__recommended if item != recommended ]
        return recommended[0]
예제 #25
0
class WebBrowser(object):
    hasBrowser = property(lambda self: self.__browser is not None)
    intializationUrl = property(lambda self: self.__baseUrl)
    baseUrl = property(lambda self:
                       ('' if self.__browser is None else self.__baseUrl))
    url = property(lambda self:
                   ('' if self.__browser is None else self.__browser.url))
    width = property(lambda self:
                     (0 if self.__browser is None else self.__browser.width))
    height = property(lambda self:
                      (0 if self.__browser is None else self.__browser.height))
    isNavigationComplete = property(lambda self: self.__isNavigationComplete)
    isFocused = property(lambda self: self.__isFocused)
    updateInterval = 0.01
    isSuccessfulLoad = property(lambda self: self.__successfulLoad)
    skipEscape = property(lambda self: self.__skipEscape)
    ignoreKeyEvents = property(lambda self: self.__ignoreKeyEvents)
    useSpecialKeys = property(lambda self: self.__useSpecialKeys)
    allowRightClick = property(lambda self: self.__allowRightClick)
    allowMouseWheel = property(lambda self: self.__allowMouseWheel)

    @skipEscape.setter
    def skipEscape(self, value):
        LOG_BROWSER('skipEscape set %s (was: %s)' % (value, self.__skipEscape))
        self.__skipEscape = value

    @ignoreKeyEvents.setter
    def ignoreKeyEvents(self, value):
        LOG_BROWSER('ignoreKeyEvents set %s (was: %s)' %
                    (value, self.__ignoreKeyEvents))
        self.__ignoreKeyEvents = value

    @useSpecialKeys.setter
    def useSpecialKeys(self, value):
        LOG_BROWSER('useSpecialKeys set %s (was: %s)' %
                    (value, self.__useSpecialKeys))
        self.__useSpecialKeys = value

    @allowRightClick.setter
    def allowRightClick(self, value):
        LOG_BROWSER('allowRightClick set %s (was: %s)' %
                    (value, self.__allowRightClick))
        self.__allowRightClick = value

    @allowMouseWheel.setter
    def allowMouseWheel(self, value):
        LOG_BROWSER('allowMouseWheel set %s (was: %s)' %
                    (value, self.__allowMouseWheel))
        self.__allowMouseWheel = value

    def __init__(self,
                 browserID,
                 uiObj,
                 texName,
                 size,
                 url='about:blank',
                 isFocused=False,
                 handlers=None):
        """
        :param browserID: id of the browser will be created
        :param uiObj: must be an object inherited from gui.Flash, which SWF should contain
                      necessary callbacks (browserDown, browserUp, browserUp)
        :param texName: name of exported texture from SWF attached to uiObj
        :param size: tuple(width, height) of mapped texture in pixels
        :param url: optioal initial URL to open
        :param isFocused: initial value for isFocused attribute
        :param handlers: list of callable functions that will be called for
                         each URL clicked on the browser page
        """
        self.__browserID = browserID
        self.__cbID = None
        self.__baseUrl = url
        self.__uiObj = uiObj
        self.__texName = texName
        self.__browserSize = size
        self.__startFocused = isFocused
        self.__browser = None
        self.__delayedUrls = []
        self.__isNavigationComplete = False
        self.__isFocused = False
        self.__navigationFilters = handlers or set()
        self.__skipEscape = True
        self.__ignoreKeyEvents = False
        self.__useSpecialKeys = True
        self.__allowRightClick = False
        self.__allowMouseWheel = True
        self.__allowAutoLoadingScreenChange = True
        self.__isCloseTriggered = False
        self.__eventMgr = EventManager()
        self.onLoadStart = Event(self.__eventMgr)
        self.onLoadEnd = Event(self.__eventMgr)
        self.onLoadingStateChange = Event(self.__eventMgr)
        self.onReadyToShowContent = Event(self.__eventMgr)
        self.onNavigate = Event(self.__eventMgr)
        self.onReady = Event(self.__eventMgr)
        self.onJsHostQuery = Event(self.__eventMgr)
        self.onTitleChange = Event(self.__eventMgr)
        self.onFailedCreation = Event(self.__eventMgr)
        self.onCanCreateNewBrowser = Event(self.__eventMgr)
        self.onUserRequestToClose = Event(self.__eventMgr)
        LOG_BROWSER('INIT ', self.__baseUrl, texName, size, self.__browserID)
        return

    def create(self):
        LOG_BROWSER('CREATE ', self.__baseUrl, self.__browserID)
        clientLanguage = helpers.getClientLanguage()
        self.__browser = BigWorld.createBrowser(self.__browserID,
                                                clientLanguage)
        if self.__browser is None:
            LOG_BROWSER('create() NO BROWSER WAS CREATED', self.__baseUrl)
            return False
        else:
            self.__browser.script = EventListener(self)
            self.__browser.script.onLoadStart += self.__onLoadStart
            self.__browser.script.onLoadEnd += self.__onLoadEnd
            self.__browser.script.onLoadingStateChange += self.__onLoadingStateChange
            self.__browser.script.onDOMReady += self.__onReadyToShowContent
            self.__browser.script.onCursorUpdated += self.__onCursorUpdated
            self.__browser.script.onReady += self.__onReady
            self.__browser.script.onJsHostQuery += self.__onJsHostQuery
            self.__browser.script.onTitleChange += self.__onTitleChange

            def injectBrowserKeyEvent(me, e):
                if _BROWSER_KEY_LOGGING:
                    LOG_BROWSER('injectBrowserKeyEvent',
                                (e.key, e.isKeyDown(), e.isAltDown(),
                                 e.isShiftDown(), e.isCtrlDown()))
                me.__browser.injectKeyEvent(e)

            def injectKeyDown(me, e):
                injectBrowserKeyEvent(me, e)

            def injectKeyUp(me, e):
                injectBrowserKeyEvent(me, e)

            def resetBit(value, bitMask):
                return value & ~bitMask

            self.__specialKeyHandlers = (
                (Keys.KEY_LEFTARROW, True, True, None, None,
                 lambda me, _: me.__browser.goBack()),
                (Keys.KEY_RIGHTARROW, True, True, None, None,
                 lambda me, _: me.__browser.goForward()),
                (Keys.KEY_F5, True, None, None, None,
                 lambda me, _: me.__browser.reload()))
            self.__browserKeyHandlers = (
                (Keys.KEY_LSHIFT, False, None, True, None,
                 lambda me, e: injectKeyUp(
                     me,
                     BigWorld.KeyEvent(e.key, e.repeatCount,
                                       resetBit(e.modifiers, 1), None, e.
                                       cursorPosition))),
                (Keys.KEY_RSHIFT, False, None, True, None,
                 lambda me, e: injectKeyUp(
                     me,
                     BigWorld.KeyEvent(e.key, e.repeatCount,
                                       resetBit(e.modifiers, 1), None, e.
                                       cursorPosition))),
                (Keys.KEY_LCONTROL, False, None, None, True,
                 lambda me, e: injectKeyUp(
                     me,
                     BigWorld.KeyEvent(e.key, e.repeatCount,
                                       resetBit(e.modifiers, 2), None, e.
                                       cursorPosition))),
                (Keys.KEY_RCONTROL, False, None, None, True,
                 lambda me, e: injectKeyUp(
                     me,
                     BigWorld.KeyEvent(e.key, e.repeatCount,
                                       resetBit(e.modifiers, 2), None, e.
                                       cursorPosition))),
                (None, True, None, None, None,
                 lambda me, e: injectKeyDown(me, e)),
                (None, False, None, None, None,
                 lambda me, e: injectKeyUp(me, e)))
            self.__disableKeyHandlers = []
            return True

    def setDisabledKeys(self, keys):
        self.__disableKeyHandlers = []
        for key, isKeyDown, isAltDown, isShiftDown, isCtrlDown in keys:
            self.__disableKeyHandlers.append(
                (key, isKeyDown, isAltDown, isShiftDown, isCtrlDown,
                 lambda me, e: None))

    def ready(self, success):
        LOG_BROWSER('READY ', success, self.__baseUrl, self.__browserID)
        self.__ui = weakref.ref(self.__uiObj)
        self.__readyToShow = False
        self.__successfulLoad = False
        self.enableUpdate = True
        self.__isMouseDown = False
        self.__isFocused = False
        self.__isWaitingForUnfocus = False
        if success:
            browserSize = self.__browserSize
            self.__browser.setScaleformRender(self.__uiObj.movie,
                                              self.__texName, browserSize[0],
                                              browserSize[1])
            self.__browser.activate(True)
            self.__browser.focus()
            self.__browser.loadURL(self.__baseUrl)
            if self.__startFocused:
                self.focus()
            self.update()
            g_mgr.addBrowser(self)
            self.onReady(self.__browser.url, success)
        else:
            self.__isNavigationComplete = True
            LOG_BROWSER(' FAILED ', self.__baseUrl, self.__browserID)
            self.onFailedCreation(self.__baseUrl)

    def updateSize(self, size):
        self.__browserSize = size
        if self.hasBrowser:
            self.__browser.resize(size[0], size[1])

    def __processDelayedNavigation(self):
        if self.__isNavigationComplete and self.__delayedUrls:
            self.doNavigate(self.__delayedUrls.pop(0))
            return True
        return False

    def destroy(self):
        self.__eventMgr.clear()
        self.__eventMgr = None
        if self.__browser is not None:
            LOG_BROWSER('DESTROYED ', self.__baseUrl, self.__browserID)
            self.__browser.script.clear()
            self.__browser.script = None
            self.__browser.resetScaleformRender(self.__uiObj.movie,
                                                self.__texName)
            BigWorld.removeBrowser(self.__browserID)
            self.__browser = None
        if self.__cbID is not None:
            BigWorld.cancelCallback(self.__cbID)
            self.__cbID = None
        self.__ui = None
        self.__navigationFilters = None
        if self.__uiObj is not None:
            self.__uiObj.cursorMgr.setCursorForced(Cursor.ARROW)
        g_mgr.delBrowser(self)
        return

    def focus(self):
        if self.hasBrowser and not self.isFocused:
            self.__browser.focus()
            self.__isFocused = True
            ui = self.__ui()
            if ui:
                ui.cursorMgr.setCursorForced(self.__browser.script.cursorType)

    def unfocus(self):
        if self.hasBrowser and self.isFocused:
            self.__browser.unfocus()
            self.__isFocused = False
            self.__isWaitingForUnfocus = False

    def refresh(self, ignoreCache=True):
        if BigWorld.time() - self.__loadStartTime < 0.5:
            LOG_BROWSER('refresh - called too soon')
            return
        if self.hasBrowser:
            self.__browser.reload()
            self.onNavigate(self.__browser.url)

    def navigate(self, url):
        lastIsSame = self.__delayedUrls and self.__delayedUrls[-1] == url
        if not lastIsSame:
            self.__delayedUrls.append(url)
        self.__processDelayedNavigation()

    def sendMessage(self, message):
        if self.hasBrowser:
            self.__browser.sendMessage(message)

    def doNavigate(self, url):
        LOG_BROWSER('doNavigate', url)
        self.__baseUrl = url
        if self.hasBrowser:
            self.__browser.script.newNavigation()
            self.__browser.loadURL(url)
            self.onNavigate(url)

    def navigateBack(self):
        if self.hasBrowser:
            self.__browser.goBack(self.url)

    def navigateForward(self):
        if self.hasBrowser:
            self.__browser.goForward(self.url)

    def navigateStop(self):
        if BigWorld.time() - self.__loadStartTime < 0.5:
            LOG_BROWSER('navigateStop - called too soon')
            return
        if self.hasBrowser:
            self.__browser.stop()
            self.__onLoadEnd(self.__browser.url)

    def update(self):
        self.__cbID = BigWorld.callback(self.updateInterval, self.update)

    def __getBrowserKeyHandler(self, key, isKeyDown, isAltDown, isShiftDown,
                               isCtrlDown):
        from itertools import izip
        params = (key, isKeyDown, isAltDown, isShiftDown, isCtrlDown)
        matches = lambda t: t[0] is None or t[0] == t[1]
        browserKeyHandlers = tuple(
            self.__disableKeyHandlers) + self.__browserKeyHandlers
        if self.useSpecialKeys:
            browserKeyHandlers = self.__specialKeyHandlers + browserKeyHandlers
        for values in browserKeyHandlers:
            if reduce(lambda a, b: a and matches(b), izip(values, params),
                      True):
                return values[-1]

        return None

    def handleKeyEvent(self, event):
        e = event
        keyState = (e.key, e.isKeyDown(), e.isAltDown(), e.isShiftDown(),
                    e.isCtrlDown())
        if not (self.hasBrowser and self.enableUpdate):
            return False
        if not self.allowRightClick and e.key == Keys.KEY_RIGHTMOUSE:
            return False
        if not self.skipEscape and e.key == Keys.KEY_ESCAPE and e.isKeyDown():
            self.__getBrowserKeyHandler(*keyState)(self, e)
            return True
        if not self.isFocused:
            self.__browser.injectKeyModifiers(e)
            return False
        if _BROWSER_KEY_LOGGING:
            LOG_BROWSER('handleKeyEvent', keyState)
        if self.ignoreKeyEvents and e.key not in (Keys.KEY_LEFTMOUSE,
                                                  Keys.KEY_RIGHTMOUSE):
            return False
        if e.key in (Keys.KEY_ESCAPE, Keys.KEY_SYSRQ):
            return False
        if e.key in (Keys.KEY_RETURN, Keys.KEY_NUMPADENTER) and e.isAltDown():
            return False
        self.__getBrowserKeyHandler(*keyState)(self, e)
        return True

    def browserMove(self, x, y, z):
        if not (self.hasBrowser and self.enableUpdate and self.isFocused):
            return
        if z != 0:
            if self.allowMouseWheel:
                self.__browser.injectMouseWheelEvent(z * 20)
            return
        self.__browser.injectMouseMoveEvent(x, y)

    def browserDown(self, x, y, z):
        if not (self.hasBrowser and self.enableUpdate):
            return
        if self.__isMouseDown:
            return
        if not self.isFocused:
            self.focus()
            self.__isMouseDown = True
            self.browserUp(x, y, z)
            self.browserMove(x, y, z)
        self.__isMouseDown = True

    def browserUp(self, x, y, z):
        if not (self.hasBrowser and self.enableUpdate):
            return
        if not self.__isMouseDown:
            return
        self.__isMouseDown = False
        if self.__isWaitingForUnfocus:
            self.unfocus()

    def browserFocusOut(self):
        if self.isFocused and self.__isMouseDown:
            self.__isWaitingForUnfocus = True
            return
        self.unfocus()

    def browserAction(self, action):
        if self.hasBrowser and self.enableUpdate:
            if action == 'reload' and self.isNavigationComplete:
                self.refresh()
            elif action == 'loading' and not self.isNavigationComplete:
                self.navigateStop()

    def onBrowserShow(self, needRefresh):
        self.enableUpdate = True
        if needRefresh and self.baseUrl != self.url:
            self.navigate(self.url)
        self.focus()

    def onBrowserHide(self):
        self.navigate(self.__baseUrl)
        self.enableUpdate = False
        self.unfocus()

    def addFilter(self, handler):
        if handler in self.__navigationFilters:
            LOG_ERROR('Navigation filter is already added', handler)
        else:
            self.__navigationFilters.add(handler)

    def removeFilter(self, handler):
        if handler in self.__navigationFilters:
            self.__navigationFilters.discard(handler)
        else:
            LOG_ERROR("Trying to delete navigation filter which doesn't exist",
                      handler)

    def filterNavigation(self, url):
        query = urlparse.urlparse(url).query
        tags = urlparse.parse_qs(query).get(_WOT_CLIENT_PARAM_NAME, [])
        stopNavigation = False
        closeBrowser = False
        for handler in self.__navigationFilters:
            try:
                result = handler(url, tags)
                stopNavigation |= result.stopNavigation
                closeBrowser |= result.closeBrowser
                if result.stopNavigation:
                    LOG_DEBUG('Navigation filter triggered navigation stop:',
                              handler)
                if result.closeBrowser:
                    LOG_DEBUG('Navigation filter triggered browser close:',
                              handler)
            except:
                LOG_CURRENT_EXCEPTION()

        self.__isCloseTriggered = closeBrowser
        return stopNavigation

    def setLoadingScreenVisible(self, visible):
        LOG_BROWSER('setLoadingScreenVisible', visible)
        self.onLoadingStateChange(visible, True)

    def setAllowAutoLoadingScreen(self, enabled):
        LOG_BROWSER('setAllowAutoLoadingScreen', enabled)
        self.__allowAutoLoadingScreenChange = enabled

    def changeTitle(self, title):
        """
        Changes title. Is used by BrowserController
        @param title:
        @return:
        """
        self.onTitleChange(title)

    def __onLoadStart(self, url):
        if url == self.__browser.url:
            self.__isNavigationComplete = False
            self.__loadStartTime = BigWorld.time()
            LOG_BROWSER('onLoadStart', self.__browser.url)
            self.onLoadStart(self.__browser.url)
            self.__readyToShow = False
            self.__successfulLoad = False

    def __onLoadEnd(self, url, isLoaded=True, httpStatusCode=None):
        if url == self.__browser.url:
            self.__isNavigationComplete = True
            self.__successfulLoad = isLoaded
            if not self.__processDelayedNavigation():
                LOG_BROWSER('onLoadEnd', self.__browser.url, isLoaded,
                            httpStatusCode)
                self.onLoadEnd(self.__browser.url, isLoaded, httpStatusCode)

    def __onLoadingStateChange(self, isLoading):
        LOG_BROWSER('onLoadingStateChange', isLoading,
                    self.__allowAutoLoadingScreenChange)
        self.onLoadingStateChange(isLoading,
                                  self.__allowAutoLoadingScreenChange)
        if self.__isCloseTriggered:
            event_dispatcher.hideWebBrowser(self.__browserID)
        elif not isLoading:
            self.onCanCreateNewBrowser()

    def __onReadyToShowContent(self, url):
        if url == self.__browser.url:
            LOG_BROWSER('onReadyToShowContent', self.__browser.url)
            self.__readyToShow = True
            self.onReadyToShowContent(self.__browser.url)

    def __isValidTitle(self, title):
        if self.__browser.url.startswith('about:'):
            return False
        if self.__browser.url.endswith(title):
            return False
        if self.__browser.url.endswith('/'):
            secondtest = self.__browser.url[:-1]
            if secondtest.endswith(title):
                return False
        if self.__baseUrl == title or self.__baseUrl.endswith(title):
            return False
        return True

    def __onTitleChange(self, title):
        if self.__isValidTitle(title):
            LOG_BROWSER('onTitleChange', title, self.__browser.url)
            self.onTitleChange(title)

    def __onCursorUpdated(self):
        if self.hasBrowser and self.isFocused:
            ui = self.__ui()
            if ui:
                ui.cursorMgr.setCursorForced(self.__browser.script.cursorType)

    def __onReady(self, success):
        self.ready(success)

    def __onJsHostQuery(self, command):
        self.onJsHostQuery(command)

    def executeJavascript(self, script, frame):
        if self.hasBrowser:
            self.__browser.executeJavascript(script, frame)
예제 #26
0
class WebBrowser(object):
    hasBrowser = property(lambda self: self.__browser is not None)
    initializationUrl = property(lambda self: self.__baseUrl)
    baseUrl = property(lambda self: ''
                       if self.__browser is None else self.__baseUrl)
    url = property(lambda self: ''
                   if self.__browser is None else self.__browser.url)
    width = property(lambda self: 0
                     if self.__browser is None else self.__browser.width)
    height = property(lambda self: 0
                      if self.__browser is None else self.__browser.height)
    isNavigationComplete = property(lambda self: self.__isNavigationComplete)
    isFocused = property(lambda self: self.__isFocused)
    isAudioPlaying = property(lambda self: self.__isAudioPlaying)
    textureUrl = property(lambda self: self.__textureUrl)
    updateInterval = 0.01
    isSuccessfulLoad = property(lambda self: self.__successfulLoad)
    skipEscape = property(lambda self: self.__skipEscape)
    ignoreKeyEvents = property(lambda self: self.__ignoreKeyEvents)
    ignoreAltKey = property(lambda self: self.__ignoreAltKey)
    ignoreCtrlClick = property(lambda self: self.__ignoreCtrlClick)
    ignoreShiftClick = property(lambda self: self.__ignoreShiftClick)
    useSpecialKeys = property(lambda self: self.__useSpecialKeys)
    allowMiddleClick = property(lambda self: self.__allowMiddleClick)
    allowRightClick = property(lambda self: self.__allowRightClick)
    allowMouseWheel = property(lambda self: self.__allowMouseWheel)

    @skipEscape.setter
    def skipEscape(self, value):
        _logger.debug('skipEscape set %s (was: %s)', value, self.__skipEscape)
        self.__skipEscape = value

    @ignoreKeyEvents.setter
    def ignoreKeyEvents(self, value):
        _logger.debug('ignoreKeyEvents set %s (was: %s)', value,
                      self.__ignoreKeyEvents)
        self.__ignoreKeyEvents = value

    @ignoreAltKey.setter
    def ignoreAltKey(self, value):
        _logger.debug('ignoreAltKey set %s (was: %s)', value,
                      self.__ignoreAltKey)
        self.__ignoreAltKey = value

    @ignoreCtrlClick.setter
    def ignoreCtrlClick(self, value):
        _logger.debug('ignoreCtrlClick set %s (was: %s)', value,
                      self.__ignoreCtrlClick)
        self.__ignoreCtrlClick = value

    @ignoreShiftClick.setter
    def ignoreShiftClick(self, value):
        _logger.debug('ignoreShiftClick set %s (was: %s)', value,
                      self.__ignoreShiftClick)
        self.__ignoreShiftClick = value

    @useSpecialKeys.setter
    def useSpecialKeys(self, value):
        _logger.debug('useSpecialKeys set %s (was: %s)', value,
                      self.__useSpecialKeys)
        self.__useSpecialKeys = value

    @allowMiddleClick.setter
    def allowMiddleClick(self, value):
        _logger.debug('allowMiddleClick set %s (was: %s)', value,
                      self.__allowMiddleClick)
        self.__allowMiddleClick = value

    @allowRightClick.setter
    def allowRightClick(self, value):
        _logger.debug('allowRightClick set %s (was: %s)', value,
                      self.__allowRightClick)
        self.__allowRightClick = value

    @allowMouseWheel.setter
    def allowMouseWheel(self, value):
        _logger.debug('allowMouseWheel set %s (was: %s)', value,
                      self.__allowMouseWheel)
        self.__allowMouseWheel = value

    def __init__(self,
                 browserID,
                 uiObj,
                 size,
                 url='about:blank',
                 isFocused=False,
                 handlers=None):
        self.__browserID = browserID
        self.__cbID = None
        self.__baseUrl = url
        self.__uiObj = uiObj
        self.__browserSize = size + (1.0, )
        self.__startFocused = isFocused
        self.__browser = None
        self.__isNavigationComplete = False
        self.__loadStartTime = None
        self.__isFocused = False
        self.__isAudioPlaying = False
        self.__navigationFilters = handlers or set()
        self.__skipEscape = True
        self.__ignoreKeyEvents = False
        self.__ignoreAltKey = False
        self.__ignoreCtrlClick = True
        self.__ignoreShiftClick = True
        self.__useSpecialKeys = True
        self.__allowMiddleClick = False
        self.__allowRightClick = False
        self.__allowMouseWheel = True
        self.__allowAutoLoadingScreenChange = True
        self.__isCloseTriggered = False
        self.__isAudioMutable = False
        self.__ctrlDown = False
        self.__shiftDown = False
        self.__textureUrl = ''
        self.__eventMgr = EventManager()
        self.onLoadStart = Event(self.__eventMgr)
        self.onLoadEnd = Event(self.__eventMgr)
        self.onLoadingStateChange = Event(self.__eventMgr)
        self.onReadyToShowContent = Event(self.__eventMgr)
        self.onNavigate = Event(self.__eventMgr)
        self.onReady = Event(self.__eventMgr)
        self.onJsHostQuery = Event(self.__eventMgr)
        self.onTitleChange = Event(self.__eventMgr)
        self.onFailedCreation = Event(self.__eventMgr)
        self.onCanCreateNewBrowser = Event(self.__eventMgr)
        self.onUserRequestToClose = Event(self.__eventMgr)
        self.onAudioStatusChanged = Event(self.__eventMgr)
        _logger.info('INIT %s size %s, id: %s', self.__baseUrl, size,
                     self.__browserID)
        levelSetting = Settings.g_instance.engineConfig['webBrowser'][
            'logVerbosity'].asString
        levelSettingEnum = LogSeverity[levelSetting]
        _webAppLogger.setLevel(
            _LOG_SEVERITY_TO_LOG_LEVEL_MAP[levelSettingEnum])
        return

    def create(self):
        _logger.info('CREATE %s id: %s', self.__baseUrl, self.__browserID)
        self.__browser = BigWorld.createWebView(self.__browserID)
        if self.__browser is None:
            _logger.error('create() NO BROWSER WAS CREATED: %s',
                          self.__baseUrl)
            return False
        else:
            self.__browser.script = EventListener(self)
            self.__browser.script.onLoadStart += self.__onLoadStart
            self.__browser.script.onLoadEnd += self.__onLoadEnd
            self.__browser.script.onLoadingStateChange += self.__onLoadingStateChange
            self.__browser.script.onDOMReady += self.__onReadyToShowContent
            self.__browser.script.onCursorUpdated += self.__onCursorUpdated
            self.__browser.script.onReady += self.__onReady
            self.__browser.script.onJsHostQuery += self.__onJsHostQuery
            self.__browser.script.onTitleChange += self.__onTitleChange
            self.__browser.script.onDestroy += self.__onDestroy
            self.__browser.script.onAudioStatusChanged += self.__onAudioStatusChanged
            self.__browser.script.onConsoleMessage += self.__onConsoleMessage
            self.__browser.script.isBrowserPlayingAudio = False

            def injectBrowserKeyEvent(me, e):
                if _BROWSER_KEY_LOGGING:
                    _logger.debug('injectBrowserKeyEvent: %s',
                                  (e.key, e.isKeyDown(), e.isAltDown(),
                                   e.isShiftDown(), e.isCtrlDown()))
                me.__browser.injectKeyEvent(e)

            def injectKeyDown(me, e):
                injectBrowserKeyEvent(me, e)

            def injectKeyUp(me, e):
                injectBrowserKeyEvent(me, e)

            def resetBit(value, bitMask):
                return value & ~bitMask

            self.__specialKeyHandlers = (
                (Keys.KEY_LEFTARROW, True, True, None, None,
                 lambda me, _: me.__browser.goBack()),
                (Keys.KEY_RIGHTARROW, True, True, None, None,
                 lambda me, _: me.__browser.goForward()),
                (Keys.KEY_F5, True, None, None, None,
                 lambda me, _: me.__browser.reload()))
            self.__browserKeyHandlers = (
                (Keys.KEY_LSHIFT, False, None, True, None,
                 lambda me, e: injectKeyUp(
                     me,
                     BigWorld.KeyEvent(e.key, e.repeatCount,
                                       resetBit(e.modifiers, 1), None, e.
                                       cursorPosition))),
                (Keys.KEY_RSHIFT, False, None, True, None,
                 lambda me, e: injectKeyUp(
                     me,
                     BigWorld.KeyEvent(e.key, e.repeatCount,
                                       resetBit(e.modifiers, 1), None, e.
                                       cursorPosition))),
                (Keys.KEY_LCONTROL, False, None, None, True,
                 lambda me, e: injectKeyUp(
                     me,
                     BigWorld.KeyEvent(e.key, e.repeatCount,
                                       resetBit(e.modifiers, 2), None, e.
                                       cursorPosition))),
                (Keys.KEY_RCONTROL, False, None, None, True,
                 lambda me, e: injectKeyUp(
                     me,
                     BigWorld.KeyEvent(e.key, e.repeatCount,
                                       resetBit(e.modifiers, 2), None, e.
                                       cursorPosition))),
                (None, True, None, None, None,
                 injectKeyDown), (None, False, None, None, None, injectKeyUp))
            self.__disableKeyHandlers = []
            return True

    def setDisabledKeys(self, keys):
        self.__disableKeyHandlers = []
        for key, isKeyDown, isAltDown, isShiftDown, isCtrlDown in keys:
            self.__disableKeyHandlers.append(
                (key, isKeyDown, isAltDown, isShiftDown, isCtrlDown,
                 lambda me, e: None))

    def ready(self, success):
        _logger.info('READY success: %r %s id: %s', success, self.__baseUrl,
                     self.__browserID)
        self.__ui = weakref.ref(self.__uiObj)
        self.__readyToShow = False
        self.__successfulLoad = False
        self.enableUpdate = True
        self.__isMouseDown = False
        self.__isFocused = False
        self.__isWaitingForUnfocus = False
        if success:
            browserSize = self.__browserSize
            self.__textureUrl = self.__browser.setScaleformRender(
                str(self.__browserID), browserSize[0], browserSize[1],
                browserSize[2])
            _logger.info('READY scaleform texture url: %s', self.__textureUrl)
            self.__browser.activate(True)
            self.__browser.focus()
            self.__browser.loadURL(self.__baseUrl)
            if self.__startFocused:
                self.focus()
            g_mgr.addBrowser(self)
            self.onReady(self.__browser.url, success)
            self.onCanCreateNewBrowser()
        else:
            self.__isNavigationComplete = True
            _logger.error(' FAILED %s id: %s', self.__baseUrl,
                          self.__browserID)
            self.onFailedCreation(self.__baseUrl)

    def invalidateView(self):
        if self.hasBrowser:
            self.__browser.invalidate()

    def updateSize(self, size):
        self.__browserSize = size
        if self.hasBrowser:
            self.__browser.resize(size[0], size[1], size[2])

    def destroy(self):
        if self.__eventMgr is not None:
            self.__eventMgr.clear()
            self.__eventMgr = None
        if self.__browser is not None:
            _logger.info('DESTROYED %s id: %s', self.__baseUrl,
                         self.__browserID)
            self.__onAudioStatusChanged(isPlaying=False)
            self.__browser.script.clear()
            self.__browser.script = None
            self.__browser.resetScaleformRender()
            BigWorld.destroyWebView(self.__browserID)
            self.__browser = None
        if self.__cbID is not None:
            BigWorld.cancelCallback(self.__cbID)
            self.__cbID = None
        self.__ui = None
        self.__navigationFilters = None
        self.__setUICursor(self.__uiObj, CursorManager.ARROW)
        g_mgr.delBrowser(self)
        return

    def focus(self):
        if self.hasBrowser and not self.isFocused:
            self.__browser.focus()
            self.__isFocused = True
            self.__setUICursor(self.__ui(), self.__browser.script.cursorType)

    def unfocus(self):
        if self.hasBrowser and self.isFocused:
            self.__browser.unfocus()
            self.__isFocused = False
            self.__isWaitingForUnfocus = False

    def refresh(self, ignoreCache=True):
        if self.__loadStartTime is None or BigWorld.time(
        ) - self.__loadStartTime < 0.5:
            _logger.debug('refresh - called too soon')
            return
        else:
            if self.hasBrowser:
                self.__browser.reload()
                self.onNavigate(self.__browser.url)
            return

    def navigate(self, url):
        _logger.debug('navigate %s', url)
        self.__baseUrl = url
        if self.hasBrowser:
            self.__browser.script.newNavigation()
            self.__browser.loadURL(url)
            self.onNavigate(url)

    def sendMessage(self, message):
        if self.hasBrowser:
            self.__browser.sendMessage(message)

    def sendEvent(self, webEvent):
        if self.hasBrowser:
            self.__browser.sendEvent(webEvent)

    def navigateBack(self):
        if self.hasBrowser:
            self.__browser.goBack(self.url)

    def navigateForward(self):
        if self.hasBrowser:
            self.__browser.goForward(self.url)

    def navigateStop(self):
        if self.__loadStartTime is None or BigWorld.time(
        ) - self.__loadStartTime < 0.5:
            _logger.debug('navigateStop - called too soon')
            return
        else:
            if self.hasBrowser:
                self.__browser.stop()
                self.__onLoadEnd(self.__browser.url)
            return

    def __getBrowserKeyHandler(self, key, isKeyDown, isAltDown, isShiftDown,
                               isCtrlDown):
        from itertools import izip
        params = (key, isKeyDown, isAltDown, isShiftDown, isCtrlDown)

        def matches(t):
            return t[0] is None or t[0] == t[1]

        browserKeyHandlers = tuple(
            self.__disableKeyHandlers) + self.__browserKeyHandlers
        if self.useSpecialKeys:
            browserKeyHandlers = self.__specialKeyHandlers + browserKeyHandlers
        for values in browserKeyHandlers:
            if functools.reduce(lambda a, b: a and matches(b),
                                izip(values, params), True):
                return values[-1]

        return None

    def handleKeyEvent(self, event):
        e = event
        keyState = (e.key, e.isKeyDown(), e.isAltDown(), e.isShiftDown(),
                    e.isCtrlDown())
        toolTipMgr = self.__uiObj.getToolTipMgr()
        if toolTipMgr and toolTipMgr.isReadyToHandleKey(event):
            return False
        if e.key in (Keys.KEY_LCONTROL, Keys.KEY_RCONTROL):
            self.__ctrlDown = e.isKeyDown()
        if self.__ignoreCtrlClick and self.__ctrlDown and e.key == Keys.KEY_LEFTMOUSE:
            return False
        if e.key in (Keys.KEY_LSHIFT, Keys.KEY_RSHIFT):
            self.__shiftDown = e.isKeyDown()
        if self.__ignoreShiftClick and self.__shiftDown and e.key == Keys.KEY_LEFTMOUSE:
            return False
        if self.__ignoreAltKey and e.key in (Keys.KEY_LALT, Keys.KEY_RALT):
            return False
        if not (self.hasBrowser and self.enableUpdate):
            return False
        if not self.allowMiddleClick and e.key == Keys.KEY_MIDDLEMOUSE:
            return False
        if not self.allowRightClick and e.key == Keys.KEY_RIGHTMOUSE:
            return False
        if not self.skipEscape and e.key == Keys.KEY_ESCAPE and e.isKeyDown():
            self.__getBrowserKeyHandler(*keyState)(self, e)
            return True
        if not self.isFocused:
            self.__browser.injectKeyModifiers(e)
            return False
        if _BROWSER_KEY_LOGGING:
            _logger.debug('handleKeyEvent %s', keyState)
        if self.ignoreKeyEvents and e.key not in (Keys.KEY_LEFTMOUSE,
                                                  Keys.KEY_RIGHTMOUSE,
                                                  Keys.KEY_MIDDLEMOUSE):
            return False
        if e.key in (Keys.KEY_ESCAPE, Keys.KEY_SYSRQ):
            return False
        if e.key in (Keys.KEY_RETURN, Keys.KEY_NUMPADENTER) and e.isAltDown():
            return False
        self.__getBrowserKeyHandler(*keyState)(self, e)
        return True

    def browserMove(self, x, y, z):
        if not (self.hasBrowser and self.enableUpdate and self.isFocused):
            return
        if z != 0:
            if self.allowMouseWheel:
                self.__browser.injectMouseWheelEvent(z * 20)
            return
        self.__browser.injectMouseMoveEvent(x, y)

    def browserDown(self, x, y, z):
        if not (self.hasBrowser and self.enableUpdate):
            return
        if self.__isMouseDown:
            return
        if not self.isFocused:
            self.focus()
            self.__isMouseDown = True
            self.browserUp(x, y, z)
            self.browserMove(x, y, z)
        self.__isMouseDown = True

    def browserUp(self, x, y, z):
        if not (self.hasBrowser and self.enableUpdate):
            return
        if not self.__isMouseDown:
            return
        self.__isMouseDown = False
        if self.__isWaitingForUnfocus:
            self.unfocus()

    def browserFocusOut(self):
        if self.isFocused and self.__isMouseDown:
            self.__isWaitingForUnfocus = True
            return
        self.unfocus()

    def browserAction(self, action):
        if self.hasBrowser and self.enableUpdate:
            if action == 'reload' and self.isNavigationComplete:
                self.refresh()
            elif action == 'loading' and not self.isNavigationComplete:
                self.navigateStop()

    def onBrowserShow(self, needRefresh):
        self.enableUpdate = True
        if needRefresh and self.baseUrl != self.url:
            self.navigate(self.url)
        self.focus()

    def onBrowserHide(self):
        self.navigate(self.__baseUrl)
        self.enableUpdate = False
        self.unfocus()

    def addFilter(self, handler):
        if handler in self.__navigationFilters:
            _logger.error('Navigation filter is already added: %r', handler)
        else:
            self.__navigationFilters.add(handler)

    def removeFilter(self, handler):
        if handler in self.__navigationFilters:
            self.__navigationFilters.discard(handler)
        else:
            _logger.error(
                "Trying to delete navigation filter which doesn't exist: %r",
                handler)

    def filterNavigation(self, url):
        query = urlparse.urlparse(url).query
        tags = urlparse.parse_qs(query).get(_WOT_CLIENT_PARAM_NAME, [])
        stopNavigation = False
        closeBrowser = False
        for handler in self.__navigationFilters:
            try:
                result = handler(url, tags)
                stopNavigation |= result.stopNavigation
                closeBrowser |= result.closeBrowser
                if result.stopNavigation:
                    _logger.debug(
                        'Navigation filter triggered navigation stop: %s',
                        handler)
                if result.closeBrowser:
                    _logger.debug(
                        'Navigation filter triggered browser close: %s',
                        handler)
            except Exception:
                LOG_CURRENT_EXCEPTION()

        self.__isCloseTriggered = closeBrowser
        return stopNavigation

    def onResourceLoadRequest(self, url):
        result = urlparse.urlparse(url)
        return result.netloc + result.path if result.scheme == _WOT_RESOURCE_CUSTOM_SCHEME else _g_webCache.get(
            url)

    def setAllowAutoLoadingScreen(self, enabled):
        _logger.debug('setAllowAutoLoadingScreen %s', enabled)
        self.__allowAutoLoadingScreenChange = enabled

    def setIsAudioMutable(self, isAudioMutable):
        self.__isAudioMutable = isAudioMutable

    def changeTitle(self, title):
        self.onTitleChange(title)

    def __onLoadStart(self, url):
        if url == self.__browser.url:
            self.__isNavigationComplete = False
            self.__loadStartTime = BigWorld.time()
            _logger.debug('onLoadStart %s', self.__browser.url)
            self.onLoadStart(self.__browser.url)
            self.__readyToShow = False
            self.__successfulLoad = False

    def __onLoadEnd(self,
                    url,
                    isLoaded=True,
                    httpStatusCode=None,
                    errorDesc=None):
        if url == self.__browser.url or errorDesc:
            self.__isNavigationComplete = True
            self.__successfulLoad = isLoaded
            if not isLoaded or httpStatusCode and httpStatusCode >= 400 or errorDesc:
                _logger.error(
                    'FAILED Url: %s, Http code: %r, Browser error: %s',
                    self.__browser.url, httpStatusCode, errorDesc)
            self.onLoadEnd(self.__browser.url, isLoaded, httpStatusCode)

    def __onLoadingStateChange(self, isLoading):
        _logger.debug('onLoadingStateChange %r %r', isLoading,
                      self.__allowAutoLoadingScreenChange)
        self.onLoadingStateChange(isLoading,
                                  self.__allowAutoLoadingScreenChange)
        if self.__isCloseTriggered:
            event_dispatcher.hideWebBrowser(self.__browserID)

    def __onReadyToShowContent(self, url):
        if url == self.__browser.url:
            _logger.debug('onReadyToShowContent %s', self.__browser.url)
            self.__readyToShow = True
            self.onReadyToShowContent(self.__browser.url)

    def __isValidTitle(self, title):
        if self.__browser.url.startswith('about:'):
            return False
        if self.__browser.url.endswith(title):
            return False
        if self.__browser.url.endswith('/'):
            secondtest = self.__browser.url[:-1]
            if secondtest.endswith(title):
                return False
        if self.__baseUrl == title or self.__baseUrl.endswith(title):
            return False
        return False if title.startswith('http://') or title.startswith(
            'https://') else True

    def __setUICursor(self, ui, cursorType):
        if ui and cursorType:
            ui.cursorMgr.setCursorForced(cursorType)

    def __onTitleChange(self, title):
        if self.__isValidTitle(title):
            _logger.debug('onTitleChange title: %s %s', title,
                          self.__browser.url)
            self.onTitleChange(title)

    def __onCursorUpdated(self):
        if self.hasBrowser and self.isFocused:
            self.__setUICursor(self.__ui(), self.__browser.script.cursorType)

    def __onReady(self, success):
        self.ready(success)

    def __onDestroy(self):
        _logger.info('Destroy Web View %s - %r', self.__baseUrl,
                     self.__browserID)
        self.destroy()

    def __onJsHostQuery(self, command):
        self.onJsHostQuery(command)

    def __onConsoleMessage(self, level, message, lineNumber, source, viewId):
        try:
            levelEnum = [l for l in LogSeverity if l.value == level][0]
        except IndexError:
            levelEnum = LogSeverity.disable

        if levelEnum != LogSeverity.disable:
            _webAppLogger.log(_LOG_SEVERITY_TO_LOG_LEVEL_MAP[levelEnum],
                              '%s, line %s, viewId %s: %s', source, lineNumber,
                              viewId, message)

    def __onAudioStatusChanged(self, isPlaying):
        if self.__isAudioMutable:
            self.__isAudioPlaying = bool(isPlaying)
            g_mgr.updateGameAudio()

    def executeJavascript(self, script, frame):
        if self.hasBrowser:
            self.__browser.executeJavascript(script, frame)
class EventsCache(IEventsCache):
    USER_QUESTS = (EVENT_TYPE.BATTLE_QUEST,
     EVENT_TYPE.TOKEN_QUEST,
     EVENT_TYPE.PERSONAL_QUEST,
     EVENT_TYPE.PERSONAL_MISSION)
    SYSTEM_QUESTS = (EVENT_TYPE.REF_SYSTEM_QUEST,)
    lobbyContext = dependency.descriptor(ILobbyContext)
    rareAchievesCache = dependency.descriptor(IRaresCache)
    linkedSet = dependency.descriptor(ILinkedSetController)

    def __init__(self):
        self.__waitForSync = False
        self.__invalidateCbID = None
        self.__cache = defaultdict(dict)
        self.__personalMissionsHidden = {}
        self.__actionsCache = defaultdict(lambda : defaultdict(dict))
        self.__actions2quests = {}
        self.__quests2actions = {}
        self.__questsDossierBonuses = defaultdict(set)
        self.__compensations = {}
        self.__personalMissions = PersonalMissionsCache()
        self.__questsProgress = QuestsProgressRequester()
        self.__em = EventManager()
        self.__prefetcher = Prefetcher(self)
        self.onSyncStarted = Event(self.__em)
        self.onSyncCompleted = Event(self.__em)
        self.onProgressUpdated = Event(self.__em)
        self.onMissionVisited = Event(self.__em)
        self.onEventsVisited = Event(self.__em)
        self.onProfileVisited = Event(self.__em)
        self.onPersonalQuestsVisited = Event(self.__em)
        self.__lockedQuestIds = {}
        return

    def init(self):
        self.__personalMissions.init()
        self.__prefetcher.init()

    def fini(self):
        self.__personalMissions.fini()
        self.__prefetcher.fini()
        self.__em.clear()
        self.__compensations.clear()
        self.__clearInvalidateCallback()

    def start(self):
        self.__lockedQuestIds = BigWorld.player().personalMissionsLock
        g_playerEvents.onPMLocksChanged += self.__onLockedQuestsChanged
        self.lobbyContext.getServerSettings().onServerSettingsChange += self.__onServerSettingsChange

    def stop(self):
        self.lobbyContext.getServerSettings().onServerSettingsChange -= self.__onServerSettingsChange
        g_playerEvents.onPMLocksChanged -= self.__onLockedQuestsChanged
        self.__clearCache()

    def clear(self):
        self.stop()
        quests_caches.clearNavInfo()

    @property
    def waitForSync(self):
        return self.__waitForSync

    @property
    def questsProgress(self):
        return self.__questsProgress

    def getPersonalMissions(self):
        return self.__personalMissions

    @property
    def prefetcher(self):
        return self.__prefetcher

    def getLockedQuestTypes(self, branch):
        questIDs = set()
        result = set()
        allQuests = self.getPersonalMissions().getQuestsForBranch(branch)
        for lockedList in self.__lockedQuestIds.values():
            if lockedList is not None:
                questIDs.update(lockedList)

        for questID in questIDs:
            if questID in allQuests:
                result.add(allQuests[questID].getMajorTag())

        return result

    @async
    @process
    def update(self, diff=None, callback=None):
        clearModifiersCache()
        yield self.getPersonalMissions().questsProgressRequest()
        if not self.getPersonalMissions().isQuestsProgressSynced():
            callback(False)
            return
        else:
            yield self.__questsProgress.request()
            if not self.__questsProgress.isSynced():
                callback(False)
                return
            isNeedToInvalidate = True
            isNeedToClearItemsCaches = False

            def _cbWrapper(*args):
                callback(*args)
                self.__personalMissions.update(self, diff)

            if diff is not None:
                isQPUpdated = 'quests' in diff or 'tokens' in diff
                isEventsDataUpdated = ('eventsData', '_r') in diff or diff.get('eventsData', {})
                isNeedToInvalidate = isQPUpdated or isEventsDataUpdated
                hasVehicleUnlocks = False
                for intCD in diff.get('stats', {}).get('unlocks', set()):
                    if getTypeOfCompactDescr(intCD) == GUI_ITEM_TYPE.VEHICLE:
                        hasVehicleUnlocks = True
                        break

                isNeedToClearItemsCaches = hasVehicleUnlocks or 'inventory' in diff and GUI_ITEM_TYPE.VEHICLE in diff['inventory']
            if isNeedToInvalidate:
                self.__invalidateData(_cbWrapper)
                return
            if isNeedToClearItemsCaches:
                self.__clearQuestsItemsCache()
            _cbWrapper(True)
            return

    def getQuests(self, filterFunc=None):
        filterFunc = filterFunc or (lambda a: True)

        def userFilterFunc(q):
            return not q.isHidden() and filterFunc(q)

        return self._getQuests(userFilterFunc)

    def getActiveQuests(self, filterFunc=None):
        filterFunc = filterFunc or (lambda a: True)

        def userFilterFunc(q):
            return False if isLinkedSet(q.getGroupID()) and not self.linkedSet.isLinkedSetEnabled() else q.getFinishTimeLeft() and filterFunc(q)

        return self.getQuests(userFilterFunc)

    def getAdvisableQuests(self, filterFunc=None):
        filterFunc = filterFunc or (lambda a: True)

        def userFilterFunc(q):
            if q.getType() == EVENT_TYPE.MOTIVE_QUEST and not q.isAvailable().isValid:
                return False
            if q.getType() == EVENT_TYPE.TOKEN_QUEST and isMarathon(q.getID()):
                return False
            return False if isLinkedSet(q.getGroupID()) and not q.isAvailable().isValid else filterFunc(q)

        return self.getActiveQuests(userFilterFunc)

    def getMotiveQuests(self, filterFunc=None):
        filterFunc = filterFunc or (lambda a: True)

        def userFilterFunc(q):
            return q.getType() == EVENT_TYPE.MOTIVE_QUEST and filterFunc(q)

        return self.getQuests(userFilterFunc)

    def getLinkedSetQuests(self, filterFunc=None):
        filterFunc = filterFunc or (lambda a: True)

        def userFilterFunc(q):
            return isLinkedSet(q.getGroupID()) and filterFunc(q)

        return self.getQuests(userFilterFunc)

    def getBattleQuests(self, filterFunc=None):
        filterFunc = filterFunc or (lambda a: True)

        def userFilterFunc(q):
            return q.getType() == EVENT_TYPE.BATTLE_QUEST and filterFunc(q)

        return self.getQuests(userFilterFunc)

    def getGroups(self, filterFunc=None):
        svrGroups = self._getQuestsGroups(filterFunc)
        svrGroups.update(self._getActionsGroups(filterFunc))
        return svrGroups

    def getHiddenQuests(self, filterFunc=None):
        filterFunc = filterFunc or (lambda a: True)

        def hiddenFilterFunc(q):
            return q.isHidden() and filterFunc(q)

        return self._getQuests(hiddenFilterFunc)

    def getRankedQuests(self, filterFunc=None):
        filterFunc = filterFunc or (lambda a: True)

        def rankedFilterFunc(q):
            return q.getType() == EVENT_TYPE.RANKED_QUEST and filterFunc(q)

        return self._getQuests(rankedFilterFunc)

    def getAllQuests(self, filterFunc=None, includePersonalMissions=False):
        return self._getQuests(filterFunc, includePersonalMissions)

    def getActions(self, filterFunc=None):
        filterFunc = filterFunc or (lambda a: True)

        def userFilterFunc(q):
            return filterFunc(q) and q.getType() != EVENT_TYPE.GROUP

        return self._getActions(userFilterFunc)

    def getActionEntities(self):
        return self.__getActionsEntitiesData()

    def getAnnouncedActions(self):
        return self.__getAnnouncedActions()

    def getEventBattles(self):
        battles = self.__getEventBattles()
        return EventBattles(battles.get('vehicleTags', set()), battles.get('vehicles', []), bool(battles.get('enabled', 0)), battles.get('arenaTypeID')) if battles else EventBattles(set(), [], 0, None)

    def isEventEnabled(self):
        return len(self.__getEventBattles()) > 0 and len(self.getEventVehicles()) > 0

    @dependency.replace_none_kwargs(itemsCache=IItemsCache)
    def getEventVehicles(self, itemsCache=None):
        result = []
        if itemsCache is None:
            return result
        else:
            for v in self.getEventBattles().vehicles:
                item = itemsCache.items.getItemByCD(v)
                if item.isInInventory:
                    result.append(item)

            return sorted(result)

    def getEvents(self, filterFunc=None):
        svrEvents = self.getQuests(filterFunc)
        svrEvents.update(self.getActions(filterFunc))
        return svrEvents

    def getCurrentEvents(self):
        return self.getEvents(lambda q: q.getStartTimeLeft() <= 0 < q.getFinishTimeLeft())

    def getFutureEvents(self):
        return self.getEvents(lambda q: q.getStartTimeLeft() > 0)

    def getAffectedAction(self, item):
        actionEntities = self.getActionEntities()
        if actionEntities:
            entities = actionEntities[aei.ENTITIES_SECTION_NAME]
            actions = actionEntities[aei.ACTIONS_SECTION_NAME]
            steps = actionEntities[aei.STEPS_SECTION_NAME]
            if item in entities:
                entity = entities[item]
                actionNameIdx = entity[aei.ACTION_NAME_IDX]
                actionName = actions[actionNameIdx]
                stepNameIdx = entity[aei.ACTION_STEP_IDX]
                actionStep = steps[stepNameIdx]
                intersectedActions = entity[aei.AFFECTED_ACTIONS_IDX]
                return [actionName, actionStep, intersectedActions]
        return []

    def getItemAction(self, item, isBuying=True, forCredits=False):
        result = []
        actionType = ACTION_MODIFIER_TYPE.DISCOUNT if isBuying else ACTION_MODIFIER_TYPE.SELLING
        itemTypeID = item.itemTypeID
        nationID = item.nationID
        intCD = item.intCD
        values = self.__actionsCache[ACTION_SECTION_TYPE.ALL][actionType].get(itemTypeID, {}).get(nationID, [])
        values += self.__actionsCache[ACTION_SECTION_TYPE.ALL][actionType].get(itemTypeID, {}).get(15, [])
        for (key, value), actionID in values:
            if item.isPremium and key in ('creditsPrice', 'creditsPriceMultiplier') and not forCredits:
                continue
            result.append((value, actionID))

        result.extend(self.__actionsCache[ACTION_SECTION_TYPE.ITEM][actionType].get(itemTypeID, {}).get(intCD, tuple()))
        return result

    def getBoosterAction(self, booster, isBuying=True, forCredits=False):
        result = []
        actionType = ACTION_MODIFIER_TYPE.DISCOUNT if isBuying else ACTION_MODIFIER_TYPE.SELLING
        boosterID = booster.boosterID
        values = self.__actionsCache[ACTION_SECTION_TYPE.ALL_BOOSTERS][actionType].get(nations.NONE_INDEX, [])
        for (key, value), actionID in values:
            if forCredits and key == 'creditsPriceMultiplier':
                result.append((value, actionID))
            if not forCredits and key == 'goldPriceMultiplier':
                result.append((value, actionID))

        result.extend(self.__actionsCache[ACTION_SECTION_TYPE.BOOSTER][actionType].get(boosterID, tuple()))
        return result

    def getRentAction(self, item, rentPackage):
        result = []
        actionType = ACTION_MODIFIER_TYPE.RENT
        itemTypeID = item.itemTypeID
        nationID = item.nationID
        intCD = item.intCD
        values = self.__actionsCache[ACTION_SECTION_TYPE.ALL][actionType].get(itemTypeID, {}).get(nationID, [])
        values += self.__actionsCache[ACTION_SECTION_TYPE.ALL][actionType].get(itemTypeID, {}).get(15, [])
        for (_, value), actionID in values:
            result.append((value, actionID))

        result.extend(self.__actionsCache[ACTION_SECTION_TYPE.ITEM][actionType].get(itemTypeID, {}).get((intCD, rentPackage), tuple()))
        return result

    def getEconomicsAction(self, name):
        result = self.__actionsCache[ACTION_SECTION_TYPE.ECONOMICS][ACTION_MODIFIER_TYPE.DISCOUNT].get(name, [])
        resultMult = self.__actionsCache[ACTION_SECTION_TYPE.ECONOMICS][ACTION_MODIFIER_TYPE.DISCOUNT].get('%sMultiplier' % name, [])
        return tuple(result + resultMult)

    def isBalancedSquadEnabled(self):
        return bool(self.__getUnitRestrictions().get('enabled', False))

    def getBalancedSquadBounds(self):
        return (self.__getUnitRestrictions().get('lowerBound', 0), self.__getUnitRestrictions().get('upperBound', 0))

    def isSquadXpFactorsEnabled(self):
        return bool(self.__getUnitXpFactors().get('enabled', False))

    def getSquadBonusLevelDistance(self):
        return set(self.__getUnitXpFactors().get('levelDistanceWithBonuses', ()))

    def getSquadPenaltyLevelDistance(self):
        return set(self.__getUnitXpFactors().get('levelDistanceWithPenalties', ()))

    def getSquadZeroBonuses(self):
        return set(self.__getUnitXpFactors().get('zeroBonusesFor', ()))

    def getQuestsDossierBonuses(self):
        return self.__questsDossierBonuses

    def getQuestsByTokenRequirement(self, token):
        result = []
        for q in self._getQuests(includePersonalMissions=True).itervalues():
            if token in [ t.getID() for t in q.accountReqs.getTokens() ]:
                result.append(q)

        return result

    def getQuestsByTokenBonus(self, token):
        result = []
        for q in self._getQuests(includePersonalMissions=True).itervalues():
            for t in q.getBonuses('tokens'):
                if token in t.getTokens().keys():
                    result.append(q)
                    break

        return result

    def getCompensation(self, tokenID):
        return self.__compensations.get(tokenID)

    def hasQuestDelayedRewards(self, questID):
        return self.__questsProgress.hasQuestDelayedRewards(questID)

    def _getQuests(self, filterFunc=None, includePersonalMissions=False):
        result = {}
        groups = {}
        filterFunc = filterFunc or (lambda a: True)
        for qID, q in self.__getCommonQuestsIterator():
            if qID in self.__quests2actions:
                q.linkedActions = self.__quests2actions[qID]
            if q.getType() == EVENT_TYPE.GROUP:
                groups[qID] = q
                continue
            if q.getFinishTimeLeft() <= 0:
                continue
            if not filterFunc(q):
                continue
            result[qID] = q

        if includePersonalMissions:
            for qID, q in self.getPersonalMissions().getAllQuests().iteritems():
                if filterFunc(q):
                    result[qID] = q

        for gID, group in groups.iteritems():
            for qID in group.getGroupEvents():
                if qID in result:
                    result[qID].setGroupID(gID)

        children, parents, parentsName = self._makeQuestsRelations(result)
        for qID, q in result.iteritems():
            if qID in children:
                q.setChildren(children[qID])
            if qID in parents:
                q.setParents(parents[qID])
            if qID in parentsName:
                q.setParentsName(parentsName[qID])

        return result

    def _getQuestsGroups(self, filterFunc=None):
        filterFunc = filterFunc or (lambda a: True)
        result = {}
        for qID, q in self.__getCommonQuestsIterator():
            if q.getType() != EVENT_TYPE.GROUP:
                continue
            if not filterFunc(q):
                continue
            result[qID] = q

        return result

    def _getActions(self, filterFunc=None):
        filterFunc = filterFunc or (lambda a: True)
        actions = self.__getActionsData()
        result = {}
        groups = {}
        for aData in actions:
            if 'id' in aData:
                a = self._makeAction(aData['id'], aData)
                actionID = a.getID()
                if actionID in self.__actions2quests:
                    a.linkedQuests = self.__actions2quests[actionID]
                if a.getType() == EVENT_TYPE.GROUP:
                    groups[actionID] = a
                    continue
                if not filterFunc(a):
                    continue
                result[actionID] = a

        for gID, group in groups.iteritems():
            for aID in group.getGroupEvents():
                if aID in result:
                    result[aID].setGroupID(gID)

        return result

    def _getActionsGroups(self, filterFunc=None):
        actions = self.__getActionsData()
        filterFunc = filterFunc or (lambda a: True)
        result = {}
        for aData in actions:
            if 'id' in aData:
                a = self._makeAction(aData['id'], aData)
                if a.getType() != EVENT_TYPE.GROUP:
                    continue
                if not filterFunc(a):
                    continue
                result[a.getID()] = a

        return result

    def _makeQuest(self, qID, qData, maker=_defaultQuestMaker, **kwargs):
        storage = self.__cache['quests']
        if qID in storage:
            return storage[qID]
        q = storage[qID] = maker(qID, qData, self.__questsProgress)
        return q

    def _makeAction(self, aID, aData):
        storage = self.__cache['actions']
        if aID in storage:
            return storage[aID]
        a = storage[aID] = createAction(aData.get('type', 0), aID, aData)
        return a

    @classmethod
    def _makeQuestsRelations(cls, quests):
        makeTokens = defaultdict(list)
        needTokens = defaultdict(list)
        for qID, q in quests.iteritems():
            if q.getType() != EVENT_TYPE.GROUP:
                tokens = q.getBonuses('tokens')
                if tokens:
                    for t in tokens[0].getTokens():
                        makeTokens[t].append(qID)

                for t in q.accountReqs.getTokens():
                    needTokens[qID].append(t.getID())

        children = defaultdict(dict)
        for parentID, tokensIDs in needTokens.iteritems():
            for tokenID in tokensIDs:
                children[parentID][tokenID] = makeTokens.get(tokenID, [])

        parents = defaultdict(lambda : defaultdict(list))
        parentsName = defaultdict(lambda : defaultdict(list))
        for parentID, tokens in children.iteritems():
            for tokenID, chn in tokens.iteritems():
                for childID in chn:
                    parents[childID][tokenID].append(parentID)
                    parentsName[childID][tokenID].append(quests[parentID].getUserName())

        return (children, parents, parentsName)

    def __invalidateData(self, callback=lambda *args: None):
        self.__clearCache()
        self.__clearInvalidateCallback()
        self.__waitForSync = True
        self.onSyncStarted()
        for action in self.getActions().itervalues():
            for modifier in action.getModifiers():
                section = modifier.getSection()
                mType = modifier.getType()
                itemType = modifier.getItemType()
                values = modifier.getValues(action)
                currentSection = self.__actionsCache[section][mType]
                if itemType is not None:
                    currentSection = currentSection.setdefault(itemType, {})
                for k in values:
                    if k in currentSection:
                        currentSection[k] += values[k]
                    currentSection[k] = values[k]

        rareAchieves = set()
        invalidateTimeLeft = sys.maxint
        for q in self.getCurrentEvents().itervalues():
            dossierBonuses = q.getBonuses('dossier')
            if dossierBonuses:
                storage = self.__questsDossierBonuses[q.getID()]
                for bonus in dossierBonuses:
                    records = bonus.getRecords()
                    storage.update(set(bonus.getRecords().keys()))
                    rareAchieves |= set((rId for r, rId in records.iteritems() if r[0] == ACHIEVEMENT_BLOCK.RARE))

            timeLeftInfo = q.getNearestActivityTimeLeft()
            if timeLeftInfo is not None:
                isAvailable, errorMsg = q.isAvailable()
                if not isAvailable:
                    if errorMsg in ('invalid_weekday', 'invalid_time_interval'):
                        invalidateTimeLeft = min(invalidateTimeLeft, timeLeftInfo[0])
                else:
                    intervalBeginTimeLeft, (intervalStart, intervalEnd) = timeLeftInfo
                    invalidateTimeLeft = min(invalidateTimeLeft, intervalBeginTimeLeft + intervalEnd - intervalStart)
            invalidateTimeLeft = min(invalidateTimeLeft, q.getFinishTimeLeft())

        self.rareAchievesCache.request(rareAchieves)
        for q in self.getFutureEvents().itervalues():
            timeLeftInfo = q.getNearestActivityTimeLeft()
            if timeLeftInfo is None:
                startTime = q.getStartTimeLeft()
            else:
                startTime = timeLeftInfo[0]
            invalidateTimeLeft = min(invalidateTimeLeft, startTime)

        if invalidateTimeLeft != sys.maxint:
            self.__loadInvalidateCallback(invalidateTimeLeft)
        self.__waitForSync = False
        self.__prefetcher.ask()
        self.__syncActionsWithQuests()
        self.__invalidateCompensations()
        self.onSyncCompleted()
        callback(True)
        return

    def __invalidateCompensations(self):
        self.__compensations.clear()
        for q in self.getHiddenQuests(lambda q: isMarathon(q.getGroupID())).itervalues():
            self.__compensations.update(q.getCompensation())

    def __clearQuestsItemsCache(self):
        for _, q in self._getQuests().iteritems():
            q.accountReqs.clearItemsCache()
            q.vehicleReqs.clearItemsCache()

    def __syncActionsWithQuests(self):
        self.__actions2quests.clear()
        self.__quests2actions.clear()
        quests = self.__cache['quests']
        actions = [ item for item in self.__cache['actions'] ]
        self.__actions2quests = {k:[] for k in actions}
        for questID, questData in quests.iteritems():
            groupId = questData.getGroupID()
            linkedActionID = getLinkedActionID(groupId, actions)
            if linkedActionID is not None:
                self.__actions2quests[linkedActionID].append(questID)

        self.__convertQuests2actions()
        return

    def __convertQuests2actions(self):
        for action, quests in self.__actions2quests.iteritems():
            for quest in quests:
                if quest in self.__quests2actions:
                    self.__quests2actions[quest].append(action)
                self.__quests2actions[quest] = [action]

    @classmethod
    def __getEventsData(cls, eventsTypeName):
        try:
            if isPlayerAccount():
                if eventsTypeName in BigWorld.player().eventsData:
                    return pickle.loads(zlib.decompress(BigWorld.player().eventsData[eventsTypeName]))
                return {}
            LOG_DEBUG('Trying to get quests data from not account player', eventsTypeName, BigWorld.player())
        except Exception:
            LOG_CURRENT_EXCEPTION()

        return {}

    def __getQuestsData(self):
        return self.__getEventsData(EVENT_CLIENT_DATA.QUEST)

    def __getPersonalQuestsData(self):
        return self.__getEventsData(EVENT_CLIENT_DATA.PERSONAL_QUEST)

    def __getActionsData(self):
        return self.__getEventsData(EVENT_CLIENT_DATA.ACTION)

    def __getActionsEntitiesData(self):
        return self.__getEventsData(EVENT_CLIENT_DATA.ACTION_ENTITIES)

    def __getAnnouncedActions(self):
        return self.__getEventsData(EVENT_CLIENT_DATA.ANNOUNCED_ACTION_DATA)

    def __getIngameEventsData(self):
        return self.__getEventsData(EVENT_CLIENT_DATA.INGAME_EVENTS)

    def __getEventBattles(self):
        return self.__getIngameEventsData().get('eventBattles', {})

    def __getUnitRestrictions(self):
        return self.__getUnitData().get('restrictions', {})

    def __getUnitXpFactors(self):
        return self.__getUnitData().get('xpFactors', {})

    def __getUnitData(self):
        return self.__getEventsData(EVENT_CLIENT_DATA.SQUAD_BONUSES)

    def __getCommonQuestsIterator(self):
        questsData = self.__getQuestsData()
        questsData.update(self.__getPersonalQuestsData())
        questsData.update(self.__getPersonalMissionsHiddenQuests())
        for qID, qData in questsData.iteritems():
            yield (qID, self._makeQuest(qID, qData))

        motiveQuests = motivation_quests.g_cache.getAllQuests() or []
        for questDescr in motiveQuests:
            yield (questDescr.questID, self._makeQuest(questDescr.questID, questDescr.questData, maker=_motiveQuestMaker))

    def __loadInvalidateCallback(self, duration):
        LOG_DEBUG('load quest window invalidation callback (secs)', duration)
        self.__clearInvalidateCallback()
        self.__invalidateCbID = BigWorld.callback(math.ceil(duration), self.__invalidateData)

    def __clearInvalidateCallback(self):
        if self.__invalidateCbID is not None:
            BigWorld.cancelCallback(self.__invalidateCbID)
            self.__invalidateCbID = None
        return

    def __clearCache(self):
        self.__questsDossierBonuses.clear()
        self.__actionsCache.clear()
        for storage in self.__cache.itervalues():
            storage.clear()

        clearModifiersCache()

    def __getPersonalMissionsHiddenQuests(self):
        if not self.__personalMissionsHidden:
            xmlPath = PERSONAL_MISSIONS_XML_PATH + '/tiles.xml'
            for quest in readQuestsFromFile(xmlPath, EVENT_TYPE.TOKEN_QUEST):
                self.__personalMissionsHidden[quest[0]] = quest[3]

        return self.__personalMissionsHidden.copy()

    def __onLockedQuestsChanged(self):
        self.__lockedQuestIds = BigWorld.player().personalMissionsLock

    def __onServerSettingsChange(self, *args, **kwargs):
        self.__personalMissions.updateDisabledStateForQuests()
예제 #28
0
class _PreDefinedHostList(object):

    def __init__(self):
        super(_PreDefinedHostList, self).__init__()
        self._eManager = EventManager()
        self.onCsisQueryStart = Event(self._eManager)
        self.onCsisQueryComplete = Event(self._eManager)
        self.onPingPerformed = Event(self._eManager)
        self._hosts = []
        self._urlMap = {}
        self._nameMap = {}
        self._peripheryMap = {}
        self._isDataLoaded = False
        self._isCSISQueryInProgress = False
        self.__csisUrl = ''
        self.__csisResponse = {}
        self.__lastRoamingHosts = []
        self.__csisCallbackID = None
        self.__lastCsisUpdateTime = 0
        self.__queryCallback = None
        self.__autoLoginQueryState = AUTO_LOGIN_QUERY_STATE.DEFAULT
        self.__csisAction = CSIS_ACTION.DEFAULT
        self.__recommended = []
        self.__pingRequester = _PingRequester(self.__onPingPerformed)
        return

    def fini(self):
        self._hosts = []
        self._urlMap.clear()
        self._nameMap.clear()
        self._peripheryMap.clear()
        self._isDataLoaded = False
        self.__csisResponse.clear()
        self.__csisUrl = ''
        self.__lastCsisUpdateTime = None
        self.__queryCallback = None
        self.__autoLoginQueryState = AUTO_LOGIN_QUERY_STATE.DEFAULT
        self.__csisAction = CSIS_ACTION.DEFAULT
        self._eManager.clear()
        self.__pingRequester.fini()
        self.__cleanCsisTimerCallback()
        return

    @property
    def lastRoamingHosts(self):
        return self.__lastRoamingHosts

    def startCSISUpdate(self):
        if len(self.hosts()) > 1:
            self.__csisAction = CSIS_ACTION.addIfNot(self.__csisAction, CSIS_ACTION.UPDATE_ON_TIME)
            self.__sendCsisQuery()

    def stopCSISUpdate(self):
        self.__csisAction = CSIS_ACTION.removeIfHas(self.__csisAction, CSIS_ACTION.UPDATE_ON_TIME)
        self.__cleanCsisTimerCallback()

    def requestPing(self, forced = False):
        self.__pingRequester.request(self._hosts, forced)

    def getPingResult(self):
        return self.__pingRequester.result()

    def autoLoginQuery(self, callback):
        if callback is None:
            LOG_WARNING('Callback is not defined.')
            return
        elif self.__autoLoginQueryState != AUTO_LOGIN_QUERY_STATE.DEFAULT:
            LOG_WARNING('Auto login query in process. Current state: {}'.format(self.__autoLoginQueryState))
            return
        elif len(self._hosts) < 2:
            callback(self.first())
            return
        elif len(self.__recommended):
            LOG_DEBUG('Gets recommended from previous query', self.__recommended)
            host = self.__choiceFromRecommended()
            LOG_DEBUG('Recommended host', host)
            callback(host)
            return
        else:
            self.__autoLoginQueryState = AUTO_LOGIN_QUERY_STATE.START
            self.__queryCallback = callback
            self.__pingRequester.request(self.peripheries())
            self.__csisAction = CSIS_ACTION.addIfNot(self.__csisAction, CSIS_ACTION.AUTO_LOGIN_REQUEST)
            self.__sendCsisQuery()
            return

    def resetQueryResult(self):
        self.__recommended = []
        self.__pingRequester.clear()

    def readScriptConfig(self, dataSection, userDataSection = None):
        if self._isDataLoaded or dataSection is None:
            return
        else:

            def _readSvrList(section, nodeName):
                if section is not None and section.has_key(nodeName):
                    return section[nodeName].items()
                else:
                    return []
                    return

            self.__csisUrl = dataSection.readString('csisUrl')
            self._hosts = []
            self._urlMap.clear()
            self._nameMap.clear()
            self._peripheryMap.clear()
            svrList = _readSvrList(dataSection, 'login') + _readSvrList(userDataSection, 'development/login')
            for name, subSec in svrList:
                name = subSec.readString('name')
                shortName = subSec.readString('short_name')
                urls = _LoginAppUrlIterator(subSec.readStrings('url'))
                host = urls.primary
                if host is not None:
                    if not len(name):
                        name = host
                    keyPath = subSec.readString('public_key_path')
                    if not len(keyPath):
                        keyPath = None
                    areaID = subSec.readString('game_area_id')
                    if not len(areaID):
                        areaID = None
                    app = self._makeHostItem(name, shortName, host, urlToken=subSec.readString('url_token'), urlIterator=urls if len(urls) > 1 else None, keyPath=keyPath, areaID=areaID, peripheryID=subSec.readInt('periphery_id', 0))
                    idx = len(self._hosts)
                    url = app.url
                    if url in self._urlMap:
                        LOG_WARNING('Host url is already added. This host is ignored', url)
                        continue
                    self._urlMap[url] = idx
                    urlToken = app.urlToken
                    if len(urlToken):
                        if urlToken in self._urlMap:
                            LOG_WARNING('Alternative host url is already added. This url is ignored', app.url)
                        else:
                            self._urlMap[urlToken] = idx
                    self._nameMap[app.name] = idx
                    if app.peripheryID:
                        self._peripheryMap[app.peripheryID] = idx
                    self._hosts.append(app)

            self._isDataLoaded = True
            return

    def predefined(self, url):
        return url in self._urlMap

    def roaming(self, url):
        return url in [ p.url for p in self.roamingHosts() ]

    def first(self):
        if len(self._hosts):
            return self._hosts[0]
        return self._makeHostItem('', '', '')

    def byUrl(self, url):
        result = self._makeHostItem('', '', url)
        index = self._urlMap.get(url, -1)
        if index > -1:
            result = self._hosts[index]
        else:
            for host in self.roamingHosts():
                if host.url == url:
                    result = host

        return result

    def byName(self, name):
        result = self._makeHostItem(name, '', '')
        index = self._nameMap.get(name, -1)
        if index > -1:
            result = self._hosts[index]
        else:
            for host in self.roamingHosts():
                if host.name == name:
                    result = host

        return result

    def hosts(self):
        return self._hosts[:]

    def shortList(self):
        result = self.getSimpleHostsList(self._hosts)
        if AUTO_LOGIN_QUERY_ENABLED and len(result) > 1 and len(self.peripheries()) > 1:
            result.insert(0, (AUTO_LOGIN_QUERY_URL,
             i18n.makeString('#menu:login/auto'),
             HOST_AVAILABILITY.IGNORED,
             None))
        return result

    def getSimpleHostsList(self, hosts):
        result = []
        defAvail = self.getDefaultCSISStatus()
        predefined = tuple((host.url for host in self.peripheries()))
        isInProgress = self._isCSISQueryInProgress
        csisResGetter = self.__csisResponse.get
        for item in hosts:
            if item.url not in predefined:
                status = HOST_AVAILABILITY.IGNORED
            else:
                status = defAvail if isInProgress else csisResGetter(item.peripheryID, defAvail)
            result.append((item.url,
             item.name,
             status,
             item.peripheryID))

        return result

    def getDefaultCSISStatus(self):
        from gui import GUI_SETTINGS
        if not len(self.__csisUrl):
            defAvail = HOST_AVAILABILITY.IGNORED
        elif GUI_SETTINGS.csisRequestRate == REQUEST_RATE.NEVER:
            defAvail = HOST_AVAILABILITY.IGNORED
        elif len(g_preDefinedHosts.hosts()) > 1:
            defAvail = HOST_AVAILABILITY.UNKNOWN
        else:
            defAvail = HOST_AVAILABILITY.IGNORED
        return defAvail

    def urlIterator(self, primary):
        result = None
        index = self._urlMap.get(primary, -1)
        if index > -1:
            result = self._hosts[index].urlIterator
        return result

    def periphery(self, peripheryID, useRoaming = True):
        if peripheryID in self._peripheryMap:
            index = self._peripheryMap[peripheryID]
            return self._hosts[index]
        else:
            if useRoaming:
                roamingHosts = dict(((host.peripheryID, host) for host in self.roamingHosts()))
                if peripheryID in roamingHosts:
                    return roamingHosts[peripheryID]
            return None

    def peripheries(self):
        return filter(lambda app: app.peripheryID, self._hosts)

    def roamingHosts(self):
        p = BigWorld.player()
        result = []
        if hasattr(p, 'serverSettings'):
            for peripheryID, name, shortName, host, keyPath in p.serverSettings['roaming'][3]:
                result.append(self._makeHostItem(name, shortName, host, keyPath=keyPath, peripheryID=peripheryID))

            self.__lastRoamingHosts = sorted(result, key=operator.itemgetter(0))
        return self.__lastRoamingHosts

    def hostsWithRoaming(self):
        predefined = tuple((host.url for host in self.peripheries()))
        hosts = self.peripheries()
        for h in self.roamingHosts():
            if h.url not in predefined:
                hosts.append(h)

        return hosts

    def isRoamingPeriphery(self, peripheryID):
        return peripheryID not in [ p.peripheryID for p in self.peripheries() ]

    def _makeHostItem(self, name, shortName, url, urlToken = '', urlIterator = None, keyPath = None, areaID = None, peripheryID = 0):
        if not len(shortName):
            shortName = name
        return _HostItem(name, shortName, url, urlToken, urlIterator, keyPath, areaID, peripheryID)

    def _determineRecommendHost(self):
        defAvail = HOST_AVAILABILITY.NOT_AVAILABLE
        csisResGetter = self.__csisResponse.get
        queryResult = map(lambda host: (host, self.__pingRequester.result().get(host.url, -1), csisResGetter(host.peripheryID, defAvail)), self.peripheries())
        self.__recommended = filter(lambda item: item[2] == HOST_AVAILABILITY.RECOMMENDED, queryResult)
        if not len(self.__recommended):
            self.__recommended = filter(lambda item: item[2] == HOST_AVAILABILITY.NOT_RECOMMENDED, queryResult)
        recommendLen = len(self.__recommended)
        if not recommendLen:
            if len(queryResult) > 1:
                LOG_DEBUG('List of recommended is empty. Gets host by ping')
                self.__recommended = self.__filterRecommendedByPing(queryResult)
                LOG_DEBUG('Recommended by ping', self.__recommended)
                result = self.__choiceFromRecommended()
            else:
                LOG_DEBUG('Gets first as recommended')
                result = self.first()
        else:
            LOG_DEBUG('Recommended by CSIS', self.__recommended)
            if recommendLen > 1:
                self.__recommended = self.__filterRecommendedByPing(self.__recommended)
                LOG_DEBUG('Recommended by ping', self.__recommended)
            result = self.__choiceFromRecommended()
        return result

    def __startCsisTimer(self):
        self.__cleanCsisTimerCallback()
        self.__csisCallbackID = BigWorld.callback(CSIS_REQUEST_TIMER, self.__onCsisTimer)

    def __cleanCsisTimerCallback(self):
        if self.__csisCallbackID:
            BigWorld.cancelCallback(self.__csisCallbackID)
            self.__csisCallbackID = None
        return

    def __onCsisTimer(self):
        self.__csisCallbackID = None
        self.__sendCsisQuery()
        return

    def __sendCsisQuery(self):
        isReplay = _isReplay('CSIS')
        if not isReplay and len(self.__csisUrl):
            if not self._isCSISQueryInProgress:
                timeFromLastUpdate = time.time() - self.__lastCsisUpdateTime
                if timeFromLastUpdate >= CSIS_REQUEST_TIMER:
                    self._isCSISQueryInProgress = True
                    self.onCsisQueryStart()
                    allHosts = self.hosts()
                    peripheries = map(lambda host: host.peripheryID, allHosts)
                    LOG_DEBUG('CSIS query sending', peripheries)
                    _CSISRequestWorker(self.__csisUrl, self.__receiveCsisResponse, peripheries).start()
                else:
                    self.__finishCsisQuery()
        else:
            if not isReplay:
                LOG_DEBUG('CSIS url is not defined - ignore')
            self._isCSISQueryInProgress = False
            self.stopCSISUpdate()
            self.__finishCsisQuery()
            self.__lastCsisUpdateTime = 0

    def __receiveCsisResponse(self, response):
        LOG_DEBUG('CSIS query received', response)
        self._isCSISQueryInProgress = False
        self.__csisResponse = response
        self.__lastCsisUpdateTime = time.time()
        self.__finishCsisQuery()

    def __finishCsisQuery(self):
        if self.__csisAction & CSIS_ACTION.AUTO_LOGIN_REQUEST:
            self.__receiveAutoLoginCSISResponse(self.__csisResponse)
        if self.__csisAction & CSIS_ACTION.UPDATE_ON_TIME:
            self.__startCsisTimer()
        self.onCsisQueryComplete(self.__csisResponse)

    def __onPingPerformed(self, result):
        self.onPingPerformed(result)
        if self.__autoLoginQueryState & AUTO_LOGIN_QUERY_STATE.START:
            self.__autoLoginQueryCompleted(AUTO_LOGIN_QUERY_STATE.PING_PERFORMED)

    def __receiveAutoLoginCSISResponse(self, response):
        self.__csisAction = CSIS_ACTION.removeIfHas(self.__csisAction, CSIS_ACTION.AUTO_LOGIN_REQUEST)
        self.__autoLoginQueryCompleted(AUTO_LOGIN_QUERY_STATE.CSIS_RESPONSE_RECEIVED)

    def __autoLoginQueryCompleted(self, state):
        if not self.__autoLoginQueryState & state:
            self.__autoLoginQueryState |= state
        if self.__autoLoginQueryState == AUTO_LOGIN_QUERY_STATE.COMPLETED:
            host = self._determineRecommendHost()
            LOG_DEBUG('Recommended host', host)
            self.__autoLoginQueryState = AUTO_LOGIN_QUERY_STATE.DEFAULT
            self.__queryCallback(host)
            self.__queryCallback = None
        return

    def __filterRecommendedByPing(self, recommended):
        result = recommended
        filtered = filter(lambda item: item[1] > -1, recommended)
        if len(filtered):
            minPingTime = min(filtered, key=lambda item: item[1])[1]
            maxPingTime = 1.2 * minPingTime
            result = filter(lambda item: item[1] < maxPingTime, filtered)
        return result

    def __choiceFromRecommended(self):
        recommended = random.choice(self.__recommended)
        self.__recommended = filter(lambda item: item != recommended, self.__recommended)
        return recommended[0]
예제 #29
0
class ConnectionManager(object):

    def __init__(self):
        self.__connectionData = ConnectionData()
        self.__connectionUrl = None
        self.__connectionMethod = CONNECTION_METHOD.BASIC
        self.__connectionStatus = LOGIN_STATUS.NOT_SET
        self.__lastLoginName = None
        self.__hostItem = g_preDefinedHosts._makeHostItem('', '', '')
        self.__retryConnectionPeriod = _MIN_RECONNECTION_TIMEOUT
        self.__retryConnectionCallbackID = None
        g_playerEvents.onKickWhileLoginReceived += self.__processKick
        g_playerEvents.onLoginQueueNumberReceived += self.__processQueue
        self.__eManager = EventManager()
        self.onLoggedOn = Event(self.__eManager)
        self.onConnected = Event(self.__eManager)
        self.onRejected = Event(self.__eManager)
        self.onDisconnected = Event(self.__eManager)
        self.onKickedFromServer = Event(self.__eManager)
        self.onKickWhileLoginReceived = Event(self.__eManager)
        self.onQueued = Event(self.__eManager)
        return

    def __del__(self):
        g_playerEvents.onKickWhileLoginReceived -= self.__processKick
        g_playerEvents.onLoginQueueNumberReceived -= self.__processQueue
        self.__eManager.clear()
        self.stopRetryConnection()

    def initiateConnection(self, params, password, serverName):
        self.__setConnectionData(params, password)
        if serverName == AUTO_LOGIN_QUERY_URL:
            g_preDefinedHosts.autoLoginQuery(self.__setHostDataAndConnect)
        else:
            self.__setHostDataAndConnect(g_preDefinedHosts.byUrl(serverName))

    def stopRetryConnection(self):
        if self.__retryConnectionCallbackID is not None:
            BigWorld.cancelCallback(self.__retryConnectionCallbackID)
            self.__retryConnectionPeriod = 0
            self.__retryConnectionCallbackID = None
        return

    def __connect(self):
        self.__retryConnectionCallbackID = None
        if constants.IS_DEVELOPMENT:
            LOG_DEBUG('Calling BigWorld.connect with params: {0}, serverName: {1}, inactivityTimeout: {2}, publicKeyPath: {3}'.format(self.__connectionData.username, self.__connectionUrl, constants.CLIENT_INACTIVITY_TIMEOUT, self.__connectionData.publicKeyPath))
        nextTick(lambda : BigWorld.connect(self.__connectionUrl, self.__connectionData, self.__serverResponseHandler))()
        if g_preDefinedHosts.predefined(self.__connectionUrl) or g_preDefinedHosts.roaming(self.__connectionUrl):
            self.__hostItem = g_preDefinedHosts.byUrl(self.__connectionUrl)
        else:
            for server in BigWorld.serverDiscovery.servers:
                if server.serverString == self.__connectionUrl:
                    self.__hostItem = self.__hostItem._replace(name=server.ownerName)
                    break

        return

    def __serverResponseHandler(self, stage, status, responseDataJSON):
        if constants.IS_DEVELOPMENT:
            LOG_DEBUG('Received server response with stage: {0}, status: {1}, responseData: {2}'.format(stage, status, responseDataJSON))
        self.__connectionStatus = status
        try:
            responseData = json.loads(responseDataJSON)
        except ValueError:
            responseData = {'errorMessage': responseDataJSON}

        if status == LOGIN_STATUS.LOGGED_ON:
            if stage == 1:
                if self.__connectionMethod == CONNECTION_METHOD.TOKEN and 'token2' in responseData:
                    self.__swtichToToken2(responseData['token2'])
                self.onLoggedOn(responseData)
                self.onConnected()
        else:
            if self.__retryConnectionCallbackID is None:
                status_ = self.__connectionStatus
                if responseData.get('errorMessage', '') == _INVALID_PASSWORD_TOKEN2_EXPIRED:
                    status_ = LOGIN_STATUS.SESSION_END
                self.onRejected(status_, responseData)
            if status == LOGIN_STATUS.LOGIN_REJECTED_RATE_LIMITED:
                self.__reconnect()
            if stage == 6:
                self.onDisconnected()
        return

    def __setConnectionData(self, params, password):
        self.__lastLoginName = params['login']
        self.__connectionMethod = params['auth_method']
        params['auth_realm'] = constants.AUTH_REALM
        m = hashlib.md5()
        m.update(params['session'])
        params['session'] = m.hexdigest()
        if constants.IS_IGR_ENABLED:
            params['is_igr'] = '1'
        username_ = json.dumps(params, encoding='utf-8')
        LOG_NOTE('User authentication method: {0}'.format(params['auth_method']))
        if 'token2' in params and params['token2']:
            password = ''
        else:
            password = pwd_token.generate(password)
        self.__connectionData.username = username_
        self.__connectionData.password = password
        self.__connectionData.inactivityTimeout = constants.CLIENT_INACTIVITY_TIMEOUT
        self.__connectionData.clientContext = json.dumps({'lang_id': getClientLanguage()})
        if constants.IS_DEVELOPMENT and params['auth_method'] == CONNECTION_METHOD.BASIC and params['login'][0] == '@':
            try:
                self.__connectionData.username = params['login'][1:]
            except IndexError:
                self.__connectionData.username = params['login']

    def __swtichToToken2(self, token2):
        self.__connectionMethod = CONNECTION_METHOD.TOKEN2
        params = json.loads(self.__connectionData.username, encoding='utf-8')
        params.pop('token', None)
        params['token2'] = token2
        params['auth_method'] = CONNECTION_METHOD.TOKEN2
        self.__connectionData.username = json.dumps(params, encoding='utf-8')
        return

    def __setHostDataAndConnect(self, predefinedHost):
        self.__connectionData.publicKeyPath = predefinedHost.keyPath
        self.__connectionUrl = predefinedHost.urlToken if (self.__connectionMethod == CONNECTION_METHOD.TOKEN or self.__connectionMethod == CONNECTION_METHOD.TOKEN2) and predefinedHost.urlToken else predefinedHost.url
        self.__connect()

    def __reconnect(self, peripheryID = 0):
        self.stopRetryConnection()
        self.__retryConnectionCallbackID = BigWorld.callback(self.__getRetryConnectionPeriod(), self.__connect)

    def __getRetryConnectionPeriod(self):
        if self.__retryConnectionPeriod != _MAX_RECONNECTION_TIMEOUT:
            self.__retryConnectionPeriod += _RECONNECTION_TIMEOUT_INCREMENT
        return self.__retryConnectionPeriod

    def __processKick(self, peripheryID):
        if peripheryID > 0:
            self.__reconnect(peripheryID)
        self.onKickWhileLoginReceived(peripheryID)

    def __processQueue(self, queueNumber):
        self.onQueued(queueNumber)

    @property
    def serverUserName(self):
        return self.__hostItem.name

    @property
    def serverUserNameShort(self):
        return self.__hostItem.shortName

    @property
    def peripheryID(self):
        return self.__hostItem.peripheryID

    @property
    def areaID(self):
        if not self.isDisconnected():
            return self.__hostItem.areaID
        else:
            return None

    @property
    def url(self):
        return self.__hostItem.url

    @property
    def loginName(self):
        if not self.isDisconnected():
            return self.__lastLoginName
        else:
            return None

    @property
    def lastLoginName(self):
        return self.__lastLoginName

    @property
    def databaseID(self):
        if not self.isDisconnected():
            return BigWorld.player().databaseID
        else:
            return None

    def disconnect(self):
        BigWorld.disconnect()

    def setKickedFromServer(self, reason, isBan, expiryTime):
        self.disconnect()
        self.onKickedFromServer(reason, isBan, expiryTime)

    def isDisconnected(self):
        return self.__connectionStatus != LOGIN_STATUS.LOGGED_ON

    def isStandalone(self):
        return self.peripheryID == 0

    def isConnected(self):
        return self.__connectionStatus == LOGIN_STATUS.LOGGED_ON

    def checkClientServerVersions(self, clientVersion, serverVersion):
        if not isValidClientVersion(clientVersion, serverVersion) or ResMgr.activeContentType() in (constants.CONTENT_TYPE.INCOMPLETE, constants.CONTENT_TYPE.TUTORIAL):
            LOG_DEBUG('Version mismatch. Client is "%s", server needs "%s".' % (clientVersion, serverVersion))
            self.onRejected(LOGIN_STATUS.LOGIN_BAD_PROTOCOL_VERSION, {})
            BigWorld.disconnect()
class _CachedVehicle(object):
    itemsCache = dependency.descriptor(IItemsCache)
    hangarSpace = dependency.descriptor(IHangarSpace)

    def __init__(self):
        self._eManager = EventManager()
        self.onChanged = Event(self._eManager)
        self.onChangeStarted = Event(self._eManager)
        self.__changeCallbackID = None
        self.__onVehicleChangedCallback = None
        return

    def init(self):
        self._addListeners()

    def destroy(self):
        self._eManager.clear()
        self._clearChangeCallback()
        self._removeListeners()

    def selectVehicle(self,
                      vehInvID=0,
                      callback=None,
                      waitingOverlapsUI=False):
        raise NotImplementedError

    def selectNoVehicle(self):
        raise NotImplementedError

    def isPresent(self):
        return self.item is not None

    def isCollectible(self):
        return self.isPresent() and self.item.isCollectible

    def refreshModel(self, outfit=None):
        raise NotImplementedError

    def updateVehicleDescriptorInModel(self):
        raise NotImplementedError

    @property
    def item(self):
        raise NotImplementedError

    @property
    def invID(self):
        raise NotImplementedError

    @property
    def intCD(self):
        raise NotImplementedError

    def _addListeners(self):
        g_clientUpdateManager.addCallbacks(
            {'inventory': self._onInventoryUpdate})
        self.itemsCache.onSyncCompleted += self._onSyncCompleted

    def _removeListeners(self):
        self.itemsCache.onSyncCompleted -= self._onSyncCompleted
        g_clientUpdateManager.removeObjectCallbacks(self)

    def _changeDone(self):
        self._clearChangeCallback()
        if isPlayerAccount():
            self._updateVehicle()
        Waiting.hide('updateCurrentVehicle')

    def _onInventoryUpdate(self, invDiff):
        raise NotImplementedError

    def _onPostProgressionUpdate(self):
        raise NotImplementedError

    def _onSyncCompleted(self, _, diff):
        if self.intCD in diff.get(GUI_ITEM_TYPE.VEH_POST_PROGRESSION, {}):
            self._onPostProgressionUpdate()

    def _updateVehicle(self):
        abilities = BigWorld.player().inventory.abilities.abilitiesManager
        scopedPerks = abilities.getPerksByVehicle(self.invID)
        if self.item:
            self.item.initPerksController(scopedPerks)
        self.onChanged()

    def _setChangeCallback(self, callback=None):
        self.__onVehicleChangedCallback = callback
        if not self.__changeCallbackID:
            self.__changeCallbackID = BigWorld.callback(0.2, self._changeDone)

    def _clearChangeCallback(self):
        if self.__onVehicleChangedCallback is not None:
            self.__onVehicleChangedCallback()
            self.__onVehicleChangedCallback = None
        if self.__changeCallbackID is not None:
            BigWorld.cancelCallback(self.__changeCallbackID)
            self.__changeCallbackID = None
        return

    def _selectVehicle(self, vehID, callback=None):
        raise NotImplementedError
class ScaleformGuiImpl(IGuiImpl):
    __slots__ = ('__proxy', '__eventMgr')
    __appLoader = dependency.descriptor(IAppLoader)

    def __init__(self):
        super(ScaleformGuiImpl, self).__init__()
        self.__proxy = None
        self.__eventMgr = EventManager()
        self.onComponentFound = Event(self.__eventMgr)
        self.onComponentDisposed = Event(self.__eventMgr)
        self.onTriggerActivated = Event(self.__eventMgr)
        self.onEffectCompleted = Event(self.__eventMgr)
        self.onInit = Event(self.__eventMgr)
        self.__appLoader.onGUISpaceBeforeEnter += self.__onBeforeEnterSpace
        return

    def fini(self):
        self.__appLoader.onGUISpaceBeforeEnter -= self.__onBeforeEnterSpace
        self.__appLoader.onGUIInitialized -= self.__setProxy
        self.clear()
        self.__eventMgr.clear()

    def clear(self):
        if self.__proxy is not None:
            self.__proxy.onCreated -= self.__onProxyCreated
            self.__proxy.onComponentFoundEvent -= self.__onComponentFound
            self.__proxy.onComponentDisposedEvent -= self.__onComponentDisposed
            self.__proxy.onEffectCompletedEvent -= self.__onEffectCompleted
            self.__proxy.onTriggerActivatedEvent -= self.__onTriggerActivated
            self.__proxy = None
        return

    def showEffect(self,
                   componentID,
                   viewID,
                   effectType,
                   effectData,
                   effectBuilder=''):
        self.__proxy.as_showEffectS(viewID, componentID, effectType, {
            'data': effectData,
            'builder': effectBuilder
        })

    def hideEffect(self, componentID, viewID, effectType, effectBuilder=''):
        self.__proxy.as_hideEffectS(viewID, componentID, effectType,
                                    effectBuilder)

    def setDescriptions(self, descriptions):
        descrs = defaultdict(list)
        for descr in descriptions:
            descrs[descr.viewId].append({
                'id': descr.ID,
                'viewName': descr.viewId,
                'path': descr.path
            })

        self.__proxy.as_setDescriptionsS(descrs)

    def setSystemEnabled(self, enabled):
        self.__proxy.as_setSystemEnabledS(enabled)

    def setCriteria(self, name, value):
        self.__proxy.as_setCriteriaS(name, value)

    def setViewCriteria(self, componentID, viewUniqueName):
        self.__proxy.as_setComponentViewCriteriaS(componentID, viewUniqueName)

    def setTriggers(self, componentID, triggers):
        self.__proxy.as_setTriggersS(componentID, triggers)

    def supportedViewTypes(self):
        return (GuiType.SCALEFORM, GuiType.WULF)

    def isInited(self):
        return self.__proxy is not None and self.__proxy.isCreated()

    def __onBeforeEnterSpace(self, spaceID):
        if spaceID in (GuiGlobalSpaceID.LOBBY, GuiGlobalSpaceID.BATTLE):
            self.__setProxy()

    def __setProxy(self):
        self.clear()
        self.__proxy = self.__appLoader.getApp().tutorialManager
        if self.__proxy is None:
            self.__appLoader.onGUIInitialized += self.__setProxy
            return
        else:
            self.__proxy.onComponentFoundEvent += self.__onComponentFound
            self.__proxy.onComponentDisposedEvent += self.__onComponentDisposed
            self.__proxy.onEffectCompletedEvent += self.__onEffectCompleted
            self.__proxy.onTriggerActivatedEvent += self.__onTriggerActivated
            self.__appLoader.onGUIInitialized -= self.__setProxy
            if not self.__proxy.isCreated():
                self.__proxy.onCreated += self.__onProxyCreated
            else:
                self.onInit()
            return

    def __onComponentFound(self, componentId, viewTutorialId):
        self.onComponentFound(componentId, viewTutorialId)

    def __onTriggerActivated(self, componentId, triggerId, state):
        self.onTriggerActivated(componentId, triggerId, state)

    def __onComponentDisposed(self, componentId):
        self.onComponentDisposed(componentId)

    def __onEffectCompleted(self, componentId, effectType):
        self.onEffectCompleted(componentId, effectType)

    def __onProxyCreated(self):
        self.onInit()
예제 #32
0
class CelebritySceneController(ICelebritySceneController):
    __slots__ = ('__eventsManager', '__celebrityEntity', '__questGroups', '__quests', '__isInChallengeView', '__tokens', '__marathonQuests', '__completedQuestsMask', '__questsCount', '__completedQuestsCount')
    __newYearController = dependency.descriptor(INewYearController)
    __eventsCache = dependency.descriptor(IEventsCache)
    __itemsCache = dependency.descriptor(IItemsCache)
    __hangarSpace = dependency.descriptor(IHangarSpace)
    __settingsCore = dependency.descriptor(ISettingsCore)

    def __init__(self):
        super(CelebritySceneController, self).__init__()
        self.__eventsManager = EventManager()
        self.onQuestsUpdated = Event(self.__eventsManager)
        self.__celebrityEntity = None
        self.__celebrityEntryEntity = None
        self.__questGroups = {}
        self.__quests = {}
        self.__tokens = {}
        self.__marathonQuests = {}
        self.__completedQuestsMask = 0
        self.__questsCount = 0
        self.__completedQuestsCount = 0
        self.__isInChallengeView = False
        return

    @property
    def isChallengeVisited(self):
        return self.__settingsCore.serverSettings.getNewYearStorage().get(NewYearStorageKeys.CELEBRITY_CHALLENGE_VISITED, False)

    @property
    def isWelcomeAnimationViewed(self):
        return self.__settingsCore.serverSettings.getNewYearStorage().get(NewYearStorageKeys.CELEBRITY_WELCOME_VIEWED, False)

    @property
    def isInChallengeView(self):
        return self.__isInChallengeView

    @property
    def isChallengeCompleted(self):
        return self.completedQuestsCount == self.questsCount

    @property
    def hasNewCompletedQuests(self):
        completedQuestsMask = self.__getCompletedQuestsMask()
        return bool(completedQuestsMask ^ self.__completedQuestsMask)

    @property
    def questGroups(self):
        return self.__questGroups

    @property
    def quests(self):
        return self.__quests

    @property
    def tokens(self):
        return self.__tokens

    @property
    def marathonQuests(self):
        return self.__marathonQuests

    @property
    def completedQuestsMask(self):
        return self.__completedQuestsMask

    @property
    def questsCount(self):
        return self.__questsCount

    @property
    def completedQuestsCount(self):
        return self.__completedQuestsCount

    def fini(self):
        self.__destroy()
        super(CelebritySceneController, self).fini()

    def onLobbyInited(self, _):
        self.__subscribe()
        self.__updateQuests()

    def onDisconnected(self):
        self.__destroy()

    def onAvatarBecomePlayer(self):
        self.__destroy()

    def addCelebrityEntity(self, entity):
        self.__celebrityEntity = entity

    def removeCelebrityEntity(self):
        self.__celebrityEntity = None
        return

    def addCelebrityEntryEntity(self, entity):
        self.__celebrityEntryEntity = entity

    def removeCelebrityEntryEntity(self):
        self.__celebrityEntryEntity = None
        return

    def onEnterChallenge(self):
        self.__isInChallengeView = True
        if self.isChallengeCompleted:
            animationTrigger = _AnimationTriggers.CHALLENGE_COMPLETED
        elif not self.isChallengeVisited and not self.isWelcomeAnimationViewed:
            animationTrigger = _AnimationTriggers.CHALLENGE_WELCOME
        elif self.hasNewCompletedQuests:
            animationTrigger = _AnimationTriggers.QUEST_COMPLETED
        else:
            animationTrigger = _AnimationTriggers.CHALLENGE_IDLE
        self.__setAnimationTrigger(animationTrigger)
        self.__saveCompletedQuestsMask()

    def onExitChallenge(self):
        self.__setAnimationTrigger(_AnimationTriggers.HANGAR_IDLE)
        self.__isInChallengeView = False

    def onSimplifyQuest(self):
        self.__setAnimationTrigger(_AnimationTriggers.QUEST_SIMPLIFIED)

    def onAnimatorEvent(self, name):
        if name == _AnimationEvents.WELCOME_COMPLETED:
            self.__settingsCore.serverSettings.saveInNewYearStorage({NewYearStorageKeys.CELEBRITY_WELCOME_VIEWED: True})

    def __destroy(self):
        self.__unsubscribe()
        self.__eventsManager.clear()
        self.__celebrityEntity = None
        self.__celebrityEntryEntity = None
        self.__questGroups.clear()
        self.__quests.clear()
        self.__tokens.clear()
        self.__marathonQuests.clear()
        self.__isInChallengeView = False
        return

    def __subscribe(self):
        self.__eventsCache.onSyncCompleted += self.__onSyncCompleted
        self.__eventsCache.onQuestConditionUpdated += self.__onSyncCompleted

    def __unsubscribe(self):
        self.__eventsCache.onSyncCompleted -= self.__onSyncCompleted
        self.__eventsCache.onQuestConditionUpdated -= self.__onSyncCompleted

    def __onSyncCompleted(self):
        self.__updateQuests()

    def __setAnimationTrigger(self, triggerName):
        if not self.__hangarSpace.spaceInited:
            return
        elif self.__celebrityEntity is None:
            _logger.error('Failed to set animation state machine trigger: %s. Missing Celebrity Entity', triggerName)
            return
        else:
            self.__celebrityEntity.setAnimatorTrigger(triggerName)
            return

    def __updateQuests(self):
        self.__questGroups = getCelebrityQuestsGroups()
        self.__quests = getCelebrityQuests()
        self.__marathonQuests = getCelebrityMarathonQuests()
        self.__tokens = getCelebrityTokens()
        self.__completedQuestsMask = 0
        for groupId, group in self.__questGroups.iteritems():
            group.update(self.quests)
            if not group.isGroupCompleted:
                continue
            dayNum = CelebrityQuestTokenParts.getDayNum(groupId)
            dayNumBit = 1 << dayNum - 1
            self.__completedQuestsMask |= dayNumBit

        self.__questsCount = getCelebrityQuestCount()
        self.__completedQuestsCount = bin(self.completedQuestsMask).count('1')
        if self.__isInChallengeView:
            self.__saveCompletedQuestsMask()
        self.onQuestsUpdated()

    def __getCompletedQuestsMask(self):
        completedQuestsMask = AccountSettings.getUIFlag(NY_CELEBRITY_QUESTS_COMPLETED_MASK)
        return completedQuestsMask

    def __saveCompletedQuestsMask(self):
        AccountSettings.setUIFlag(NY_CELEBRITY_QUESTS_COMPLETED_MASK, self.__completedQuestsMask)
예제 #33
0
class PQController(object):
    def __init__(self, eventsCache):
        self.__clearCaches()
        self.__eventsCache = weakref.proxy(eventsCache)
        self.__em = EventManager()
        self.__hasQuestsForSelect = False
        self.__hasQuestsForReward = False
        self.onSelectedQuestsChanged = Event(self.__em)
        self.onSlotsCountChanged = Event(self.__em)
        self.onProgressUpdated = Event(self.__em)

    def init(self):
        for _, potapovQuestID in potapov_quests.g_cache:
            quest = self.__makeQuest(potapovQuestID)
            tile = self.__makeTile(quest.getTileID())
            tile._addQuest(quest)
            season = self.__makeSeason(tile.getSeasonID())
            season._addTile(tile)
            quest.setSeasonID(season.getID())

    def fini(self):
        self.__em.clear()
        self.__clearCaches()

    def update(self, diff=None):
        if diff is not None:
            potapovQuestsDiff = diff.get("potapovQuests", {})
            if "selected" in potapovQuestsDiff:
                self.onSelectedQuestsChanged(potapovQuestsDiff["selected"])
            if "slots" in potapovQuestsDiff:
                self.onSlotsCountChanged(potapovQuestsDiff["slots"])
            isNeedToUpdateProgress = len(potapovQuestsDiff)
        else:
            isNeedToUpdateProgress = True
        if isNeedToUpdateProgress:
            self.__hasQuestsForSelect = False
            self.__hasQuestsForReward = False
            freeSlotsCount = self.__eventsCache.questsProgress.getPotapovQuestsFreeSlots()
            for qID, quest in self.__quests.iteritems():
                quest.updateProgress(self.__eventsCache)

            selectedQuests = self.__eventsCache.questsProgress.getSelectedPotapovQuestsIDs()
            selectedChains = set([self.__quests[questID].getChainID() for questID in selectedQuests])
            for qID, quest in self.__quests.iteritems():
                if (
                    not self.__hasQuestsForSelect
                    and freeSlotsCount
                    and quest.canBeSelected()
                    and quest.getChainID() not in selectedChains
                ):
                    self.__hasQuestsForSelect = True
                if not self.__hasQuestsForReward and quest.needToGetReward():
                    self.__hasQuestsForReward = True
                if self.__hasQuestsForSelect and self.__hasQuestsForReward:
                    break

            for tile in self.__tiles.itervalues():
                tile.updateProgress(self.__eventsCache)

            for season in self.__seasons.itervalues():
                season.updateProgress(self.__eventsCache)

            self.onProgressUpdated()
        return

    def getNextTankwomanIDs(self, nationID, isPremium, fnGroup, lnGroup, iGroupID):
        lastFirstNameID, lastLastNameID, lastIconID = self.__eventsCache.questsProgress.getTankmanLastIDs(nationID)
        return map(
            operator.itemgetter(1),
            tankmen.getNextUniqueIDs(
                BigWorld.player().databaseID,
                lastFirstNameID,
                lastLastNameID,
                lastIconID,
                nationID,
                isPremium,
                fnGroup,
                lnGroup,
                iGroupID,
            ),
        )

    def getQuests(self):
        return self.__quests

    def getTiles(self):
        return self.__tiles

    def getSeasons(self):
        return self.__seasons

    def getSelectedQuests(self):
        result = {}
        for qID in self.__eventsCache.questsProgress.getSelectedPotapovQuestsIDs():
            result[qID] = self.__quests[qID]

        return result

    def getTokens(self):
        result = set()
        for tile in self.getTiles().itervalues():
            result |= tile.getTokens().keys()

        return result

    def hasQuestsForSelect(self):
        return self.__hasQuestsForSelect

    def hasQuestsForReward(self):
        return self.__hasQuestsForReward

    def __clearCaches(self):
        self.__seasons = {}
        self.__tiles = {}
        self.__quests = {}

    def __makeSeason(self, seasonID):
        if seasonID not in self.__seasons:
            season = self.__seasons[seasonID] = event_items.PQSeason(
                seasonID, potapov_quests.g_seasonCache.getSeasonInfo(seasonID)
            )
        else:
            season = self.__seasons[seasonID]
        return season

    def __makeTile(self, tileID):
        if tileID not in self.__tiles:
            tile = self.__tiles[tileID] = event_items.PQTile(tileID, potapov_quests.g_tileCache.getTileInfo(tileID))
        else:
            tile = self.__tiles[tileID]
        return tile

    def __makeQuest(self, pqID, seasonID=None):
        if pqID not in self.__quests:
            pqType = potapov_quests.g_cache.questByPotapovQuestID(pqID)
            quest = self.__quests[pqID] = event_items.PotapovQuest(pqID, pqType, seasonID=seasonID)
        else:
            quest = self.__quests[pqID]
        return quest
class TabsContainer(object):
    eventsCache = dependency.descriptor(IEventsCache)
    goodiesCache = dependency.descriptor(IGoodiesCache)

    def __init__(self):
        self.__tabs = {TABS_IDS.INVENTORY: InventoryBoostersTab(),
         TABS_IDS.SHOP: ShopBoostersTab()}
        self.__currentTabIdx = None
        self.__activeBoostersCount = None
        self.__eManager = EventManager()
        self.onTabsUpdate = Event(self.__eManager)
        return

    def init(self):
        self.__activeBoostersCount = len(self.goodiesCache.getBoosters(criteria=REQ_CRITERIA.BOOSTER.ACTIVE).values())
        g_clientUpdateManager.addCallbacks({'goodies': self.__onUpdateBoosters,
         'shop': self.__onUpdateBoosters,
         'stats': self.__onStatsChanged})

    def setCurrentTabIdx(self, currentTabIdx):
        self.__currentTabIdx = currentTabIdx

    @property
    def currentTab(self):
        return self.__tabs[self.__currentTabIdx]

    @property
    def inventoryTab(self):
        return self.__tabs[TABS_IDS.INVENTORY]

    @property
    def shopTab(self):
        return self.__tabs[TABS_IDS.SHOP]

    def getTabs(self):
        return self.__tabs

    def setFilters(self, qualities, boosterTypes):
        for tab in self.__tabs.itervalues():
            tab.setFilters(qualities, boosterTypes)

    def getActiveBoostersCount(self):
        return self.__activeBoostersCount

    def fini(self):
        self.__currentTabIdx = None
        self.__eManager.clear()
        g_clientUpdateManager.removeObjectCallbacks(self)
        for tab in self.__tabs.itervalues():
            tab.fini()

        self.__tabs.clear()
        self.__activeBoostersCount = None
        return

    def __onUpdateBoosters(self, *args):
        for tab in self.__tabs.itervalues():
            tab.update()

        self.__activeBoostersCount = len(self.goodiesCache.getBoosters(criteria=REQ_CRITERIA.BOOSTER.ACTIVE).values())
        self.onTabsUpdate()

    def __onStatsChanged(self, stats):
        if Money.hasMoney(stats):
            self.shopTab.updateBalance()
            self.onTabsUpdate()
예제 #35
0
class _PreDefinedHostList(object):
    def __init__(self):
        super(_PreDefinedHostList, self).__init__()
        self._eManager = EventManager()
        self.onCsisQueryStart = Event(self._eManager)
        self.onCsisQueryComplete = Event(self._eManager)
        self._hosts = []
        self._urlMap = {}
        self._nameMap = {}
        self._peripheryMap = {}
        self._isDataLoaded = False
        self._isCSISQueryInProgress = False
        self.__pingResult = {}
        self.__csisUrl = ''
        self.__csisResponse = {}
        self.__lastRoamingHosts = []
        self.__csisCallbackID = None
        self.__lastCsisUpdateTime = 0
        self.__queryCallback = None
        self.__autoLoginQueryState = AUTO_LOGIN_QUERY_STATE.DEFAULT
        self.__csisAction = CSIS_ACTION.DEFAULT
        self.__recommended = []
        self.__setPingCallback = False
        try:
            BigWorld.WGPinger.setOnPingCallback(self.__onPingPerformed)
            self.__setPingCallback = True
        except AttributeError:
            LOG_CURRENT_EXCEPTION()

    def fini(self):
        self._hosts = []
        self._urlMap.clear()
        self._nameMap.clear()
        self._peripheryMap.clear()
        self._isDataLoaded = False
        self.__pingResult.clear()
        self.__csisResponse.clear()
        self.__csisUrl = ''
        self.__lastCsisUpdateTime = None
        self.__queryCallback = None
        self.__autoLoginQueryState = AUTO_LOGIN_QUERY_STATE.DEFAULT
        self.__csisAction = CSIS_ACTION.DEFAULT
        self._eManager.clear()
        self.__setPingCallback = False
        self.__cleanCsisTimerCallback()
        try:
            BigWorld.WGPinger.clearOnPingCallback()
        except AttributeError:
            LOG_CURRENT_EXCEPTION()

    @property
    def lastRoamingHosts(self):
        return self.__lastRoamingHosts

    def startCSISUpdate(self):
        if len(self.hosts()) > 1:
            self.__csisAction = CSIS_ACTION.addIfNot(
                self.__csisAction, CSIS_ACTION.UPDATE_ON_TIME)
            self.__sendCsisQuery()

    def stopCSISUpdate(self):
        self.__csisAction = CSIS_ACTION.removeIfHas(self.__csisAction,
                                                    CSIS_ACTION.UPDATE_ON_TIME)
        self.__cleanCsisTimerCallback()

    def autoLoginQuery(self, callback):
        if callback is None:
            LOG_WARNING('Callback is not defined.')
            return
        if self.__autoLoginQueryState != AUTO_LOGIN_QUERY_STATE.DEFAULT:
            LOG_WARNING('Auto login query in process.')
            return
        if len(self._hosts) < 2:
            callback(self.first())
            return
        peripheryID, expired = self.readPeripheryTL()
        if peripheryID > 0 and expired > 0:
            if expired > time.time():
                host = self.periphery(peripheryID)
                if host is not None:
                    LOG_DEBUG('Recommended host taken from cache', host)
                    callback(host)
                    return
        if len(self.__recommended):
            LOG_DEBUG('Gets recommended from previous query',
                      self.__recommended)
            host = self.__choiceFromRecommended()
            LOG_DEBUG('Recommended host', host)
            callback(host)
            return
        self.__autoLoginQueryState = AUTO_LOGIN_QUERY_STATE.START
        self.__queryCallback = callback
        self.__ping()
        self.__csisAction = CSIS_ACTION.addIfNot(
            self.__csisAction, CSIS_ACTION.AUTO_LOGIN_REQUEST)
        self.__sendCsisQuery()

    def resetQueryResult(self):
        self.__recommended = []
        self.__pingResult.clear()

    def savePeripheryTL(self, peripheryID, delta=STORED_AS_RECOMMEND_DELTA):
        if not AUTO_LOGIN_QUERY_ENABLED or not peripheryID:
            return
        try:
            loginSec = Settings.g_instance.userPrefs[Settings.KEY_LOGIN_INFO]
            if loginSec is not None:
                value = base64.b64encode(
                    pickle.dumps((peripheryID, time.time() + delta)))
                loginSec.writeString('peripheryLifeTime', value)
                Settings.g_instance.save()
        except Exception:
            LOG_CURRENT_EXCEPTION()

    def readPeripheryTL(self):
        if not AUTO_LOGIN_QUERY_ENABLED:
            return (0, 0)
        result = (0, 0)
        try:
            loginSec = Settings.g_instance.userPrefs[Settings.KEY_LOGIN_INFO]
            if loginSec is not None:
                value = loginSec.readString('peripheryLifeTime')
                if len(value):
                    value = pickle.loads(base64.b64decode(value))
                    if len(value) > 1:
                        result = value
        except Exception:
            result = ('', 0)
            LOG_CURRENT_EXCEPTION()

        return result

    def clearPeripheryTL(self):
        if not AUTO_LOGIN_QUERY_ENABLED:
            return
        try:
            loginSec = Settings.g_instance.userPrefs[Settings.KEY_LOGIN_INFO]
            if loginSec is not None:
                loginSec.writeString('peripheryLifeTime', '')
                Settings.g_instance.save()
        except Exception:
            LOG_CURRENT_EXCEPTION()

    def readScriptConfig(self, dataSection):
        if self._isDataLoaded or dataSection is None:
            return
        self.__csisUrl = dataSection.readString('csisUrl')
        self._hosts = []
        self._urlMap.clear()
        self._nameMap.clear()
        self._peripheryMap.clear()
        loginSection = dataSection['login']
        if loginSection is None:
            return
        for name, subSec in loginSection.items():
            name = subSec.readString('name')
            shortName = subSec.readString('short_name')
            urls = _LoginAppUrlIterator(subSec.readStrings('url'))
            host = urls.primary
            if host is not None:
                if not len(name):
                    name = host
                keyPath = subSec.readString('public_key_path')
                if not len(keyPath):
                    keyPath = None
                areaID = subSec.readString('game_area_id')
                if not len(areaID):
                    areaID = None
                app = self._makeHostItem(
                    name,
                    shortName,
                    host,
                    urlToken=subSec.readString('url_token'),
                    urlIterator=urls if len(urls) > 1 else None,
                    keyPath=keyPath,
                    areaID=areaID,
                    peripheryID=subSec.readInt('periphery_id', 0))
                idx = len(self._hosts)
                url = app.url
                if url in self._urlMap:
                    LOG_ERROR(
                        'Host url is already added. This host is ignored', url)
                    continue
                self._urlMap[url] = idx
                urlToken = app.urlToken
                if len(urlToken):
                    if urlToken in self._urlMap:
                        LOG_ERROR(
                            'Alternative host url is already added. This url is ignored',
                            app.url)
                    else:
                        self._urlMap[urlToken] = idx
                self._nameMap[app.name] = idx
                if app.peripheryID:
                    self._peripheryMap[app.peripheryID] = idx
                self._hosts.append(app)

        self._isDataLoaded = True

    def predefined(self, url):
        return url in self._urlMap

    def roaming(self, url):
        return url in [p.url for p in self.roamingHosts()]

    def first(self):
        if len(self._hosts):
            return self._hosts[0]
        return self._makeHostItem('', '', '')

    def byUrl(self, url):
        result = self._makeHostItem('', '', url)
        index = self._urlMap.get(url, -1)
        if index > -1:
            result = self._hosts[index]
        else:
            for host in self.roamingHosts():
                if host.url == url:
                    result = host

        return result

    def byName(self, name):
        result = self._makeHostItem(name, '', '')
        index = self._nameMap.get(name, -1)
        if index > -1:
            result = self._hosts[index]
        else:
            for host in self.roamingHosts():
                if host.name == name:
                    result = host

        return result

    def hosts(self):
        return self._hosts[:]

    def shortList(self):
        result = self.getSimpleHostsList(self._hosts)
        if AUTO_LOGIN_QUERY_ENABLED and len(result) > 1 and len(
                self.peripheries()) > 1:
            result.insert(
                0, (AUTO_LOGIN_QUERY_URL, i18n.makeString('#menu:login/auto'),
                    HOST_AVAILABILITY.IGNORED, None))
        return result

    def getSimpleHostsList(self, hosts):
        result = []
        defAvail = HOST_AVAILABILITY.getDefault()
        predefined = tuple((host.url for host in self.peripheries()))
        isInProgress = self._isCSISQueryInProgress
        csisResGetter = self.__csisResponse.get
        for item in hosts:
            if item.url not in predefined:
                status = HOST_AVAILABILITY.IGNORED
            else:
                status = defAvail if isInProgress else csisResGetter(
                    item.peripheryID, defAvail)
            result.append((item.url, item.name, status, item.peripheryID))

        return result

    def urlIterator(self, primary):
        result = None
        index = self._urlMap.get(primary, -1)
        if index > -1:
            result = self._hosts[index].urlIterator
        return result

    def periphery(self, peripheryID):
        if peripheryID in self._peripheryMap:
            index = self._peripheryMap[peripheryID]
            return self._hosts[index]
        roamingHosts = dict(
            ((host.peripheryID, host) for host in self.roamingHosts()))
        if peripheryID in roamingHosts:
            return roamingHosts[peripheryID]

    def peripheries(self):
        return filter(lambda app: app.peripheryID, self._hosts)

    def roamingHosts(self):
        p = BigWorld.player()
        result = []
        if hasattr(p, 'serverSettings'):
            for peripheryID, name, shortName, host, keyPath in p.serverSettings[
                    'roaming'][3]:
                result.append(
                    self._makeHostItem(name,
                                       shortName,
                                       host,
                                       keyPath=keyPath,
                                       peripheryID=peripheryID))

            self.__lastRoamingHosts = sorted(result,
                                             key=operator.itemgetter(0))
        return self.__lastRoamingHosts

    def hostsWithRoaming(self):
        predefined = tuple((host.url for host in self.peripheries()))
        hosts = self.peripheries()
        for h in self.roamingHosts():
            if h.url not in predefined:
                hosts.append(h)

        return hosts

    def isRoamingPeriphery(self, peripheryID):
        return peripheryID not in [p.peripheryID for p in self.peripheries()]

    def _makeHostItem(self,
                      name,
                      shortName,
                      url,
                      urlToken='',
                      urlIterator=None,
                      keyPath=None,
                      areaID=None,
                      peripheryID=0):
        if not len(shortName):
            shortName = name
        return _HostItem(name, shortName, url, urlToken, urlIterator, keyPath,
                         areaID, peripheryID)

    def _determineRecommendHost(self):
        defAvail = HOST_AVAILABILITY.NOT_AVAILABLE
        pResGetter = self.__pingResult.get
        csisResGetter = self.__csisResponse.get
        queryResult = map(
            lambda host: (host, pResGetter(host.url, -1),
                          csisResGetter(host.peripheryID, defAvail)),
            self.peripheries())
        self.__recommended = filter(
            lambda item: item[2] == HOST_AVAILABILITY.RECOMMENDED, queryResult)
        if not len(self.__recommended):
            self.__recommended = filter(
                lambda item: item[2] == HOST_AVAILABILITY.NOT_RECOMMENDED,
                queryResult)
        recommendLen = len(self.__recommended)
        if not recommendLen:
            if len(queryResult) > 1:
                LOG_DEBUG('List of recommended is empty. Gets host by ping')
                self.__recommended = self.__filterRecommendedByPing(
                    queryResult)
                LOG_DEBUG('Recommended by ping', self.__recommended)
                result = self.__choiceFromRecommended()
            else:
                LOG_DEBUG('Gets first as recommended')
                result = self.first()
        else:
            LOG_DEBUG('Recommended by CSIS', self.__recommended)
            if recommendLen > 1:
                self.__recommended = self.__filterRecommendedByPing(
                    self.__recommended)
                LOG_DEBUG('Recommended by ping', self.__recommended)
            result = self.__choiceFromRecommended()
        return result

    def __ping(self):
        if not self.__setPingCallback:
            self.__onPingPerformed([])
            return
        try:
            peripheries = map(lambda host: host.url, self.peripheries())
            LOG_DEBUG('Ping starting', peripheries)
            BigWorld.WGPinger.ping(peripheries)
        except (AttributeError, TypeError):
            LOG_CURRENT_EXCEPTION()
            self.__onPingPerformed([])

    def __onPingPerformed(self, result):
        LOG_DEBUG('Ping performed', result)
        try:
            self.__pingResult = dict(result)
            self.__autoLoginQueryCompleted(
                AUTO_LOGIN_QUERY_STATE.PING_PERFORMED)
        except Exception:
            LOG_CURRENT_EXCEPTION()
            self.__pingResult = {}

    def __startCsisTimer(self):
        self.__cleanCsisTimerCallback()
        self.__csisCallbackID = BigWorld.callback(CSIS_REQUEST_TIMER,
                                                  self.__onCsisTimer)

    def __cleanCsisTimerCallback(self):
        if self.__csisCallbackID:
            BigWorld.cancelCallback(self.__csisCallbackID)
            self.__csisCallbackID = None

    def __onCsisTimer(self):
        self.__csisCallbackID = None
        self.__sendCsisQuery()

    def __sendCsisQuery(self):
        if len(self.__csisUrl):
            if not self._isCSISQueryInProgress:
                timeFromLastUpdate = time.time() - self.__lastCsisUpdateTime
                if timeFromLastUpdate >= CSIS_REQUEST_TIMER:
                    self._isCSISQueryInProgress = True
                    self.onCsisQueryStart()
                    allHosts = self.hosts()
                    peripheries = map(lambda host: host.peripheryID, allHosts)
                    LOG_DEBUG('CSIS query sending', peripheries)
                    _CSISRequestWorker(self.__csisUrl,
                                       self.__receiveCsisResponse,
                                       peripheries).start()
                else:
                    self.__finishCsisQuery()
        else:
            LOG_DEBUG('CSIS url is not defined - ignore')
            self._isCSISQueryInProgress = False
            self.stopCSISUpdate()
            self.__finishCsisQuery()
            self.__lastCsisUpdateTime = 0

    def __receiveCsisResponse(self, response):
        LOG_DEBUG('CSIS query received', response)
        self._isCSISQueryInProgress = False
        self.__csisResponse = response
        self.__lastCsisUpdateTime = time.time()
        self.__finishCsisQuery()

    def __finishCsisQuery(self):
        if self.__csisAction & CSIS_ACTION.AUTO_LOGIN_REQUEST:
            self.__receiveAutoLoginCSISResponse(self.__csisResponse)
        if self.__csisAction & CSIS_ACTION.UPDATE_ON_TIME:
            self.__startCsisTimer()
        self.onCsisQueryComplete(self.__csisResponse)

    def __receiveAutoLoginCSISResponse(self, response):
        self.__csisAction = CSIS_ACTION.removeIfHas(
            self.__csisAction, CSIS_ACTION.AUTO_LOGIN_REQUEST)
        self.__autoLoginQueryCompleted(
            AUTO_LOGIN_QUERY_STATE.CSIS_RESPONSE_RECEIVED)

    def __autoLoginQueryCompleted(self, state):
        if not self.__autoLoginQueryState & state:
            self.__autoLoginQueryState |= state
        if self.__autoLoginQueryState == AUTO_LOGIN_QUERY_STATE.COMPLETED:
            host = self._determineRecommendHost()
            LOG_DEBUG('Recommended host', host)
            self.__autoLoginQueryState = AUTO_LOGIN_QUERY_STATE.DEFAULT
            self.__queryCallback(host)
            self.__queryCallback = None

    def __filterRecommendedByPing(self, recommended):
        result = recommended
        filtered = filter(lambda item: item[1] > -1, recommended)
        if len(filtered):
            minPingTime = min(filtered, key=lambda item: item[1])[1]
            maxPingTime = 1.2 * minPingTime
            result = filter(lambda item: item[1] < maxPingTime, filtered)
        return result

    def __choiceFromRecommended(self):
        recommended = random.choice(self.__recommended)
        self.__recommended = filter(lambda item: item != recommended,
                                    self.__recommended)
        return recommended[0]
class LobbyContext(ILobbyContext):
    connectionMgr = dependency.descriptor(IConnectionManager)

    def __init__(self):
        super(LobbyContext, self).__init__()
        self.__credentials = None
        self.__guiCtx = {}
        self.__arenaUniqueIDs = {}
        self.__serverSettings = ServerSettings({})
        self.__battlesCount = None
        self.__epicBattlesCount = None
        self.__clientArenaIDGenerator = Int32IDGenerator()
        self.__headerNavigationConfirmators = set()
        self.__fightButtonConfirmators = set()
        self.__changeListener = LobbyContextChangeListener(self)
        self.__em = EventManager()
        self.onServerSettingsChanged = Event(self.__em)
        return

    def clear(self):
        self.__headerNavigationConfirmators.clear()
        self.__fightButtonConfirmators.clear()
        self.__credentials = None
        self.__battlesCount = None
        self.__guiCtx.clear()
        self.__arenaUniqueIDs.clear()
        if self.__serverSettings:
            self.__serverSettings.clear()
        self.__em.clear()
        return

    def onAccountBecomePlayer(self):
        self.setServerSettings(BigWorld.player().serverSettings)

    def onAccountShowGUI(self, ctx):
        self.__guiCtx = ctx or {}

    def getArenaUniqueIDByClientID(self, clientArenaID):
        for arenaUniqueID, cArenaID in self.__arenaUniqueIDs.iteritems():
            if cArenaID == clientArenaID:
                return arenaUniqueID

    def getClientIDByArenaUniqueID(self, arenaUniqueID):
        if arenaUniqueID in self.__arenaUniqueIDs:
            return self.__arenaUniqueIDs[arenaUniqueID]
        clientID = self.__clientArenaIDGenerator.next()
        self.__arenaUniqueIDs[arenaUniqueID] = clientID
        return clientID

    def setCredentials(self, login, token):
        self.__credentials = (login, token)

    def getCredentials(self):
        return self.__credentials

    def getBattlesCount(self):
        return self.__battlesCount

    def getEpicBattlesCount(self):
        return self.__epicBattlesCount

    def updateBattlesCount(self, battlesCount, epicBattlesCount):
        self.__battlesCount = battlesCount
        self.__epicBattlesCount = epicBattlesCount

    def update(self, diff):
        if self.__serverSettings:
            if 'serverSettings' in diff:
                self.__notifyToUpdate(diff['serverSettings'])
                self.__changeListener.update(diff['serverSettings'])
                self.__serverSettings.update(diff['serverSettings'])
            elif ('serverSettings', '_r') in diff:
                self.__notifyToUpdate(diff[('serverSettings', '_r')])
                self.__changeListener.update(diff[('serverSettings', '_r')])
                self.__serverSettings.set(diff[('serverSettings', '_r')])

    def updateGuiCtx(self, ctx):
        self.__guiCtx.update(ctx)

    def getGuiCtx(self):
        return self.__guiCtx

    @property
    def collectUiStats(self):
        return self.__guiCtx.get('collectUiStats', True)

    @property
    def needLogUXEvents(self):
        return self.__guiCtx.get('logUXEvents', False)

    def getServerSettings(self):
        return self.__serverSettings

    def setServerSettings(self, serverSettings):
        if self.__serverSettings:
            self.__serverSettings.clear()
        self.__serverSettings = ServerSettings(serverSettings)
        self.onServerSettingsChanged(self.__serverSettings)

    def getPlayerFullName(self,
                          pName,
                          clanInfo=None,
                          clanAbbrev=None,
                          regionCode=None,
                          pDBID=None):
        fullName = pName
        if clanInfo and len(clanInfo) > 1:
            clanAbbrev = clanInfo[1]
        if clanAbbrev:
            fullName = '{0:>s} [{1:>s}]'.format(pName, clanAbbrev)
        if pDBID is not None:
            regionCode = self.getRegionCode(pDBID)
        if regionCode:
            fullName = '{0:>s} {1:>s}'.format(fullName, regionCode)
        return fullName

    def getClanAbbrev(self, clanInfo):
        clanAbbrev = None
        if clanInfo and len(clanInfo) > 1:
            clanAbbrev = clanInfo[1]
        return clanAbbrev

    def getRegionCode(self, dbID):
        regionCode = None
        serverSettings = self.getServerSettings()
        if serverSettings is not None:
            roaming = serverSettings.roaming
            if dbID and not roaming.isSameRealm(dbID):
                _, regionCode = roaming.getPlayerHome(dbID)
        return regionCode

    def isAnotherPeriphery(self, peripheryID):
        if not self._isSkipPeripheryChecking():
            return self.connectionMgr.peripheryID != peripheryID
        LOG_NOTE('Skip periphery checking in standalone mode')
        return False

    @dependency.replace_none_kwargs(itemsCache=IItemsCache)
    def isPeripheryAvailable(self, peripheryID, itemsCache=None):
        result = True
        if self._isSkipPeripheryChecking():
            LOG_NOTE('Skip periphery checking in standalone mode')
            return result
        else:
            if g_preDefinedHosts.periphery(peripheryID) is None:
                LOG_ERROR('Periphery not found', peripheryID)
                result = False
            elif self.__credentials is None:
                LOG_ERROR('Login info not found', peripheryID)
                result = False
            elif g_preDefinedHosts.isRoamingPeriphery(
                    peripheryID
            ) and itemsCache is not None and not isRoamingEnabled(
                    itemsCache.items.stats.attributes):
                LOG_ERROR('Roaming is not supported', peripheryID)
                result = False
            return result

    def getPeripheryName(self, peripheryID, checkAnother=True):
        name = None
        if not checkAnother or self.isAnotherPeriphery(peripheryID):
            host = g_preDefinedHosts.periphery(peripheryID)
            if host is not None:
                name = host.name
        return name

    def addHeaderNavigationConfirmator(self, confirmator):
        self.__headerNavigationConfirmators.add(confirmator)

    def deleteHeaderNavigationConfirmator(self, confirmator):
        if confirmator in self.__headerNavigationConfirmators:
            self.__headerNavigationConfirmators.remove(confirmator)

    @async
    @process
    def isHeaderNavigationPossible(self, callback=None):
        for confirmator in self.__headerNavigationConfirmators:
            confirmed = yield confirmator()
            if not confirmed:
                callback(False)

        callback(True)

    def addFightButtonConfirmator(self, confirmator):
        self.__fightButtonConfirmators.add(confirmator)

    def deleteFightButtonConfirmator(self, confirmator):
        if confirmator in self.__fightButtonConfirmators:
            self.__fightButtonConfirmators.remove(confirmator)

    @async
    @process
    def isFightButtonPressPossible(self, callback=None):
        for confirmator in self.__fightButtonConfirmators:
            confirmed = yield confirmator()
            if not confirmed:
                callback(False)

        callback(True)

    @classmethod
    def _isSkipPeripheryChecking(cls):
        return cls.connectionMgr.isStandalone() and CURRENT_REALM == 'CT'

    @dependency.replace_none_kwargs(itemsCache=IItemsCache)
    def __notifyToUpdate(self, diff, itemsCache=None):
        if 'lootBoxes_config' in diff:
            itemsCache.items.tokens.updateAllLootBoxes(
                diff['lootBoxes_config'])
예제 #37
0
class RefSystem(Controller):

    def __init__(self, proxy):
        super(RefSystem, self).__init__(proxy)
        self.__referrers = []
        self.__referrals = []
        self.__quests = []
        self.__xpPoolOfDeletedRals = 0
        self.__totalXP = 0
        self.__isTotallyCompleted = False
        self.__posByXPinTeam = 0
        self.__eventMgr = EventManager()
        self.onUpdated = Event(self.__eventMgr)
        self.onQuestsUpdated = Event(self.__eventMgr)
        self.onPlayerBecomeReferrer = Event(self.__eventMgr)
        self.onPlayerBecomeReferral = Event(self.__eventMgr)

    @storage_getter('users')
    def usersStorage(self):
        return None

    def fini(self):
        self.__referrers = None
        self.__referrals = None
        self.__eventMgr.clear()
        self.__clearQuestsData()
        super(RefSystem, self).fini()

    def onLobbyStarted(self, ctx):
        g_clientUpdateManager.addCallbacks({'stats.refSystem': self.__onRefStatsUpdated})
        g_eventsCache.onSyncCompleted += self.__onEventsUpdated
        g_playerEvents.onShopResync += self.__onShopUpdated
        self.__update(g_itemsCache.items.stats.refSystem)
        self.__updateQuests()

    def onAvatarBecomePlayer(self):
        self.__stop()

    def onDisconnected(self):
        self.__stop()

    def getReferrers(self):
        return self.__referrers

    def getReferrals(self):
        return self.__referrals

    def getQuests(self):
        return self.__quests

    def isTotallyCompleted(self):
        return self.__isTotallyCompleted

    def getPosByXPinTeam(self):
        return self.__posByXPinTeam

    def getTotalXP(self):
        return self.__totalXP

    def getReferralsXPPool(self):
        result = self.__xpPoolOfDeletedRals
        for i in self.getReferrals():
            result += i.getXPPool()

        return result

    def getAvailableReferralsCount(self):
        return _getMaxNumberOfReferrals() - len(self.__referrals)

    def showTankmanAwardWindow(self, tankman, completedQuestIDs):
        LOG_DEBUG('Referrer has been get tankman award', tankman, completedQuestIDs)
        curXp, nextXp, _ = self.__getAwardParams(completedQuestIDs)
        shared_events.showAwardWindow(TankmanAward(tankman, curXp, nextXp))

    def showVehicleAwardWindow(self, vehicle, completedQuestIDs):
        LOG_DEBUG('Referrer has been get vehicle award', vehicle, completedQuestIDs)
        curXp, nextXp, isBoughtVehicle = self.__getAwardParams(completedQuestIDs)
        shared_events.showAwardWindow(VehicleAward(vehicle, isBoughtVehicle, curXp))

    def showCreditsAwardWindow(self, creditsValue, completedQuestIDs):
        if creditsValue > 0:
            LOG_DEBUG('Referrer has been get credits award', creditsValue, completedQuestIDs)
            shared_events.showAwardWindow(CreditsAward(creditsValue))

    @classmethod
    def getRefPeriods(cls):
        return _getRefSystemPeriods()

    @classmethod
    def getMaxReferralXPPool(cls):
        return _getMaxReferralXPPool()

    @classmethod
    def getMaxNumberOfReferrals(cls):
        return _getMaxNumberOfReferrals()

    @classmethod
    def isReferrer(cls):
        refSystemStats = g_itemsCache.items.stats.refSystem
        return refSystemStats.get('activeInvitations', 0) > 0 or len(refSystemStats.get('referrals', {})) > 0

    def showReferrerIntroWindow(self, invitesCount):
        g_eventBus.handleEvent(events.LoadViewEvent(VIEW_ALIAS.REFERRAL_REFERRER_INTRO_WINDOW, ctx={'invitesCount': invitesCount}))
        self.onPlayerBecomeReferrer()

    def showReferralIntroWindow(self, nickname, isNewbie = False):
        g_eventBus.handleEvent(events.LoadViewEvent(VIEW_ALIAS.REFERRAL_REFERRALS_INTRO_WINDOW, ctx={'referrerName': nickname,
         'newbie': isNewbie}))
        self.onPlayerBecomeReferral()

    def __stop(self):
        g_playerEvents.onShopResync -= self.__onShopUpdated
        g_eventsCache.onSyncCompleted -= self.__onEventsUpdated
        g_clientUpdateManager.removeObjectCallbacks(self)

    def __getAwardParams(self, completedQuestIDs):
        completedQuestID = completedQuestIDs.pop() if len(completedQuestIDs) else -1
        currentXP = nextXP = None
        for xp, quests in reversed(self.getQuests()):
            if completedQuestID in map(methodcaller('getID'), quests):
                currentXP = xp
                break
            else:
                nextXP = xp

        return (currentXP, nextXP, self.getReferralsXPPool() < self.getTotalXP())

    def __clearQuestsData(self):
        self.__quests = []
        self.__isTotallyCompleted = False
        self.__totalXP = 0

    def __update(self, data):
        self.__referrers = []
        self.__referrals = []
        self.__xpPoolOfDeletedRals = 0
        self.__posByXPinTeam = g_itemsCache.items.shop.refSystem['posByXPinTeam']
        storage = self.usersStorage
        userGetter = storage.getUser
        userSetter = storage.addUser
        storage.removeTags({USER_TAG.REFERRER, USER_TAG.REFERRAL})

        def updateUser(item, tags):
            dbID = item.getAccountDBID()
            user = userGetter(dbID)
            if user:
                user.addTags(tags)
                if USER_TAG.INVALID_NAME in user.getTags():
                    user.update(name=item.getNickName())
            else:
                userSetter(SharedUserEntity(dbID, name=item.getNickName(), tags=tags, clanInfo=ClanInfo(abbrev=item.getClanAbbrev())))

        for referrer in self.__buildReferrers(data):
            self.__referrers.append(referrer)
            updateUser(referrer, {USER_TAG.REFERRER})

        for referral in self.__buildReferrals(data):
            self.__referrals.append(referral)
            updateUser(referral, {USER_TAG.REFERRAL})

        self.onUpdated()
        g_messengerEvents.users.onUsersListReceived({USER_TAG.REFERRER, USER_TAG.REFERRAL})

    @classmethod
    def __makeRefItem(cls, dbID, **data):
        try:
            return _RefItem(dbID, **data)
        except:
            LOG_ERROR('There is error while building ref system item')
            LOG_CURRENT_EXCEPTION()

    def __buildReferrers(self, data):
        for key, item in (data.get('referrers') or {}).iteritems():
            referrer = self.__makeRefItem(key, **item)
            if referrer is not None:
                yield referrer

    def __buildReferrals(self, data):
        for key, item in (data.get('referrals') or {}).iteritems():
            if key == 'xpPoolOfDeletedRals':
                self.__xpPoolOfDeletedRals = item
            else:
                referral = self.__makeRefItem(key, **item)
                if referral is not None:
                    yield referral

    def __updateQuests(self):
        self.__clearQuestsData()
        refSystemQuests = g_eventsCache.getHiddenQuests(lambda x: x.getType() == EVENT_TYPE.REF_SYSTEM_QUEST)
        if refSystemQuests:
            self.__quests = self.__mapQuests(refSystemQuests.values())
            self.__totalXP, _ = self.__quests[-1]
            notCompleted = findFirst(lambda q: not q.isCompleted(), refSystemQuests.values())
            self.__isTotallyCompleted = notCompleted is None
        self.onQuestsUpdated()

    @classmethod
    def __mapQuests(cls, events):
        result = defaultdict(list)
        for event in sorted(events, key=methodcaller('getID')):
            result[event.accountReqs.getConditions().find('refSystemRalXPPool').getValue()].append(event)

        return sorted(result.iteritems(), key=itemgetter(0))

    def __onRefStatsUpdated(self, diff):
        self.__update(g_itemsCache.items.stats.refSystem)

    def __onEventsUpdated(self):
        self.__updateQuests()

    def __onShopUpdated(self):
        self.__update(g_itemsCache.items.stats.refSystem)
        self.__updateQuests()
class ConnectionManager(IConnectionManager):
    def __init__(self):
        self.__connectionData = ConnectionData()
        self.__connectionUrl = None
        self.__connectionMethod = CONNECTION_METHOD.BASIC
        self.__connectionStatus = LOGIN_STATUS.NOT_SET
        self.__lastLoginName = None
        self.__hostItem = g_preDefinedHosts._makeHostItem('', '', '')
        self.__retryConnectionPeriod = _MIN_RECONNECTION_TIMEOUT
        self.__retryConnectionCallbackID = None
        g_playerEvents.onKickWhileLoginReceived += self.__processKick
        g_playerEvents.onLoginQueueNumberReceived += self.__processQueue
        self.__eManager = EventManager()
        self.onLoggedOn = Event(self.__eManager)
        self.onConnected = Event(self.__eManager)
        self.onRejected = Event(self.__eManager)
        self.onDisconnected = Event(self.__eManager)
        self.onKickedFromServer = Event(self.__eManager)
        self.onKickWhileLoginReceived = Event(self.__eManager)
        self.onQueued = Event(self.__eManager)
        return

    def fini(self):
        g_playerEvents.onKickWhileLoginReceived -= self.__processKick
        g_playerEvents.onLoginQueueNumberReceived -= self.__processQueue
        self.__eManager.clear()
        self.stopRetryConnection()

    def initiateConnection(self, params, password, serverName):
        self.__setConnectionData(params, password)
        if serverName == AUTO_LOGIN_QUERY_URL:
            g_preDefinedHosts.autoLoginQuery(self.__setHostDataAndConnect)
        else:
            self.__setHostDataAndConnect(g_preDefinedHosts.byUrl(serverName))

    def stopRetryConnection(self):
        if self.__retryConnectionCallbackID is not None:
            BigWorld.cancelCallback(self.__retryConnectionCallbackID)
            self.__retryConnectionPeriod = 0
            self.__retryConnectionCallbackID = None
        return

    @uniprof.regionDecorator(label='offline.connect', scope='enter')
    def __connect(self):
        self.__retryConnectionCallbackID = None
        if constants.IS_DEVELOPMENT:
            LOG_DEBUG(
                'Calling BigWorld.connect with params: {0}, serverName: {1}, inactivityTimeout: {2}, publicKeyPath: {3}'
                .format(self.__connectionData.username, self.__connectionUrl,
                        constants.CLIENT_INACTIVITY_TIMEOUT,
                        self.__connectionData.publicKeyPath))
        nextTick(lambda: BigWorld.
                 connect(self.__connectionUrl, self.__connectionData, self.
                         __serverResponseHandler))()
        if g_preDefinedHosts.predefined(
                self.__connectionUrl) or g_preDefinedHosts.roaming(
                    self.__connectionUrl):
            self.__hostItem = g_preDefinedHosts.byUrl(self.__connectionUrl)
        else:
            for server in BigWorld.serverDiscovery.servers:
                if server.serverString == self.__connectionUrl:
                    self.__hostItem = self.__hostItem._replace(
                        name=server.ownerName, shortName=server.ownerName)
                    break
            else:
                self.__hostItem = self.__hostItem._replace(
                    name=self.__connectionUrl, shortName=self.__connectionUrl)

        return

    @uniprof.regionDecorator(label='offline.connect', scope='exit')
    def __serverResponseHandler(self, stage, status, responseDataJSON):
        if constants.IS_DEVELOPMENT:
            LOG_DEBUG(
                'Received server response with stage: {0}, status: {1}, responseData: {2}'
                .format(stage, status, responseDataJSON))
        self.__connectionStatus = status
        try:
            responseData = json.loads(responseDataJSON)
        except ValueError:
            responseData = {'errorMessage': responseDataJSON}

        if status == LOGIN_STATUS.LOGGED_ON:
            if stage == 1:
                if self.__connectionMethod == CONNECTION_METHOD.TOKEN and 'token2' in responseData:
                    self.__swtichToToken2(responseData['token2'])
                self.onLoggedOn(responseData)
                self.onConnected()
        else:
            if self.__retryConnectionCallbackID is None:
                status_ = self.__connectionStatus
                errorMsg = responseData.get('errorMessage', '')
                if errorMsg in INVALID_TOKEN2_EXPIRED:
                    status_ = LOGIN_STATUS.SESSION_END
                self.onRejected(status_, responseData)
            if status == LOGIN_STATUS.LOGIN_REJECTED_RATE_LIMITED:
                self.__reconnect()
            if stage == 6:
                self.onDisconnected()
                g_playerEvents.onDisconnected()
        return

    def __setConnectionData(self, params, password):
        self.__connectionMethod = params['auth_method']
        if 'auth_realm' not in params:
            params['auth_realm'] = constants.AUTH_REALM
        m = hashlib.md5()
        m.update(params['session'])
        params['session'] = m.hexdigest()
        if constants.IS_IGR_ENABLED:
            params['is_igr'] = '1'
        username_ = json.dumps(params, encoding='utf-8')
        LOG_NOTE('User authentication method: {0}'.format(
            params['auth_method']))
        if 'token2' in params and params['token2']:
            password = ''
        else:
            password = pwd_token.generate(password)
        self.__connectionData.username = username_
        self.__connectionData.password = password
        self.__connectionData.inactivityTimeout = constants.CLIENT_INACTIVITY_TIMEOUT
        self.__connectionData.clientContext = json.dumps(
            {'lang_id': getClientLanguage()})
        if constants.IS_DEVELOPMENT and params[
                'auth_method'] == CONNECTION_METHOD.BASIC and params['login'][
                    0] == '@':
            try:
                self.__connectionData.username = params['login'][1:]
            except IndexError:
                self.__connectionData.username = params['login']

    def __swtichToToken2(self, token2):
        self.__connectionMethod = CONNECTION_METHOD.TOKEN2
        params = json.loads(self.__connectionData.username, encoding='utf-8')
        params.pop('token', None)
        params['token2'] = token2
        params['auth_method'] = CONNECTION_METHOD.TOKEN2
        self.__connectionData.username = json.dumps(params, encoding='utf-8')
        return

    def __setHostData(self, predefinedHost):
        self.__connectionData.publicKeyPath = predefinedHost.keyPath
        self.__connectionUrl = predefinedHost.urlToken if (
            self.__connectionMethod == CONNECTION_METHOD.TOKEN
            or self.__connectionMethod == CONNECTION_METHOD.TOKEN2
        ) and predefinedHost.urlToken else predefinedHost.url

    def __setHostDataAndConnect(self, predefinedHost):
        self.__setHostData(predefinedHost)
        self.__connect()

    def __reconnect(self):
        self.stopRetryConnection()
        self.__retryConnectionCallbackID = BigWorld.callback(
            self.__getRetryConnectionPeriod(), self.__connect)

    def __getRetryConnectionPeriod(self):
        if self.__retryConnectionPeriod != _MAX_RECONNECTION_TIMEOUT:
            self.__retryConnectionPeriod += _RECONNECTION_TIMEOUT_INCREMENT
        return self.__retryConnectionPeriod

    def __processKick(self, peripheryID):
        if peripheryID > 0:
            host = g_preDefinedHosts.periphery(peripheryID, False)
            if host is not None:
                self.__setHostData(host)
            self.__reconnect()
        self.onKickWhileLoginReceived(peripheryID)
        return

    def __processQueue(self, queueNumber):
        self.onQueued(queueNumber)

    @property
    def serverUserName(self):
        return self.__hostItem.name

    @property
    def serverUserNameShort(self):
        return self.__hostItem.shortName

    @property
    def peripheryID(self):
        return self.__hostItem.peripheryID

    @property
    def areaID(self):
        return self.__hostItem.areaID if not self.isDisconnected() else None

    @property
    def url(self):
        return self.__hostItem.url

    @property
    def loginName(self):
        return self.__lastLoginName if not self.isDisconnected() else None

    @property
    def lastLoginName(self):
        return self.__lastLoginName

    @property
    def databaseID(self):
        return BigWorld.player(
        ).databaseID if not self.isDisconnected() else None

    @property
    def connectionMethod(self):
        return self.__connectionMethod

    def disconnect(self):
        BigWorld.disconnect()

    def setKickedFromServer(self, reason, isBan, expiryTime):
        self.disconnect()
        self.onKickedFromServer(reason, isBan, expiryTime)

    def isDisconnected(self):
        return self.__connectionStatus != LOGIN_STATUS.LOGGED_ON

    def isStandalone(self):
        return self.peripheryID == 0

    def isConnected(self):
        return self.__connectionStatus == LOGIN_STATUS.LOGGED_ON

    def checkClientServerVersions(self, clientVersion, serverVersion):
        if not isValidClientVersion(clientVersion,
                                    serverVersion) or ResMgr.activeContentType(
                                    ) in (constants.CONTENT_TYPE.INCOMPLETE,
                                          constants.CONTENT_TYPE.TUTORIAL):
            LOG_DEBUG('Version mismatch. Client is "%s", server needs "%s".' %
                      (clientVersion, serverVersion))
            self.onRejected(LOGIN_STATUS.LOGIN_BAD_PROTOCOL_VERSION, {})
            BigWorld.disconnect()

    def setLastLogin(self, email):
        self.__lastLoginName = email
예제 #39
0
class FunRandomController(IFunRandomController, Notifiable, SeasonProvider,
                          IGlobalListener):
    _ALERT_DATA_CLASS = FunRandomAlertData
    __itemsCache = dependency.descriptor(IItemsCache)
    __lobbyContext = dependency.descriptor(ILobbyContext)

    def __init__(self):
        super(FunRandomController, self).__init__()
        self.__em = EventManager()
        self.onUpdated = Event(self.__em)
        self.onGameModeStatusTick = Event(self.__em)
        self.onGameModeStatusUpdated = Event(self.__em)
        self.__serverSettings = None
        self.__funRandomSettings = None
        self.__modifiersDataProvider = ModifiersDataProvider()
        return

    def init(self):
        super(FunRandomController, self).init()
        self.addNotificator(
            SimpleNotifier(self.getTimer, self.__gameModeStatusUpdate))
        self.addNotificator(
            TimerNotifier(self.getTimer, self.__gameModeStatusTick))

    def fini(self):
        self.__em.clear()
        self.clearNotification()
        super(FunRandomController, self).fini()

    def onAccountBecomePlayer(self):
        self.__onServerSettingsChanged(self.__lobbyContext.getServerSettings())

    def onAccountBecomeNonPlayer(self):
        self.stopNotification()
        self.stopGlobalListening()

    def onDisconnected(self):
        self.stopNotification()
        self.stopGlobalListening()
        if self.__serverSettings is not None:
            self.__serverSettings.onServerSettingsChange -= self.__onServerSettingsUpdate
        self.__serverSettings = self.__funRandomSettings = self.__modifiersDataProvider = None
        return

    def onLobbyInited(self, event=None):
        self.startNotification()
        self.startGlobalListening()

    def isAvailable(self):
        return self.isBattlesPossible() and not self.isFrozen()

    def isBattlesPossible(self):
        return self.isEnabled() and self.getCurrentSeason() is not None

    def isEnabled(self):
        return self.__funRandomSettings.isEnabled

    def isFunRandomPrbActive(self):
        return False if self.prbEntity is None else bool(
            self.prbEntity.getModeFlags() & FUNCTIONAL_FLAG.FUN_RANDOM)

    def isSuitableVehicle(self, vehicle, isSquad=False):
        restriction = ''
        ctx = {}
        settings = self.__funRandomSettings
        state, _ = vehicle.getState()
        restrictions = UNIT_RESTRICTION if isSquad else PRE_QUEUE_RESTRICTION
        if state == Vehicle.VEHICLE_STATE.UNSUITABLE_TO_QUEUE or vehicle.compactDescr in settings.forbiddenVehTypes:
            restriction = restrictions.LIMIT_VEHICLE_TYPE
            ctx = {'forbiddenType': vehicle.shortUserName}
        if vehicle.type in settings.forbiddenClassTags:
            restriction = restrictions.LIMIT_VEHICLE_CLASS
            ctx = {'forbiddenClass': vehicle.type}
        if vehicle.level not in settings.levels:
            restriction = restrictions.LIMIT_LEVEL
            ctx = {'levels': settings.levels}
        return ValidationResult(False, restriction,
                                ctx) if restriction else None

    def isSuitableVehicleAvailable(self):
        criteria = self.__getSuitableVehiclesCriteria(REQ_CRITERIA.UNLOCKED)
        criteria |= ~REQ_CRITERIA.VEHICLE.SECRET | ~REQ_CRITERIA.HIDDEN | ~REQ_CRITERIA.VEHICLE.PREMIUM
        unlockedVehicles = self.__itemsCache.items.getVehicles(criteria)
        return len(unlockedVehicles) > 0

    def canGoToMode(self):
        return self.hasSuitableVehicles() or self.isSuitableVehicleAvailable()

    def hasSuitableVehicles(self):
        criteria = self.__getSuitableVehiclesCriteria(REQ_CRITERIA.INVENTORY)
        criteria |= ~REQ_CRITERIA.VEHICLE.EXPIRED_RENT
        return len(self.__itemsCache.items.getVehicles(criteria)) > 0

    def getAlertBlock(self):
        if self.hasSuitableVehicles():
            alertData = self._getAlertBlockData()
            buttonCallback = event_dispatcher.showFunRandomPrimeTimeWindow
        else:
            alertData = self._ALERT_DATA_CLASS.constructNoVehicles()
            buttonCallback = event_dispatcher.showFunRandomInfoPage
        return (buttonCallback, alertData
                or self._ALERT_DATA_CLASS(), alertData is not None)

    def getModeSettings(self):
        return self.__funRandomSettings

    def getModifiersDataProvider(self):
        return self.__modifiersDataProvider

    @adisp.process
    def selectFunRandomBattle(self):
        dispatcher = self.prbDispatcher
        if dispatcher is None:
            _logger.error('Prebattle dispatcher is not defined')
            return
        else:
            yield dispatcher.doSelectAction(
                PrbAction(PREBATTLE_ACTION_NAME.FUN_RANDOM))
            return

    def _createSeason(self, cycleInfo, seasonData):
        return FunRandomSeason(cycleInfo, seasonData,
                               self.__funRandomSettings.eventID)

    def __onServerSettingsChanged(self, serverSettings):
        if self.__serverSettings is not None:
            self.__serverSettings.onServerSettingsChange -= self.__onServerSettingsUpdate
        self.__serverSettings = serverSettings
        self.__serverSettings.onServerSettingsChange += self.__onServerSettingsUpdate
        self.__updateFunRandomSettings()
        return

    def __onServerSettingsUpdate(self, diff):
        if Configs.FUN_RANDOM_CONFIG.value in diff:
            self.__updateFunRandomSettings()

    def __getSuitableVehiclesCriteria(self, criteria):
        criteria = criteria | REQ_CRITERIA.VEHICLE.LEVELS(
            self.__funRandomSettings.levels)
        criteria |= ~REQ_CRITERIA.VEHICLE.CLASSES(
            self.__funRandomSettings.forbiddenClassTags)
        criteria |= ~REQ_CRITERIA.VEHICLE.SPECIFIC_BY_CD(
            self.__funRandomSettings.forbiddenVehTypes)
        criteria |= ~REQ_CRITERIA.VEHICLE.HAS_TAGS(
            BATTLE_MODE_VEH_TAGS_EXCEPT_FUN)
        return criteria

    def __gameModeStatusTick(self):
        self.onGameModeStatusTick()

    def __gameModeStatusUpdate(self):
        status, _, _ = self.getPrimeTimeStatus()
        self.onGameModeStatusUpdated(status)

    def __resetGameModeStatusTimers(self):
        self.startNotification()
        self.__gameModeStatusUpdate()
        self.__gameModeStatusTick()

    def __updateFunRandomSettings(self):
        self.__funRandomSettings = self.__serverSettings.funRandomConfig
        self.__modifiersDataProvider = ModifiersDataProvider(
            self.__funRandomSettings.battleModifiersDescr)
        self.__rememberGameMode()
        self.__resetGameModeStatusTimers()
        self.onUpdated()

    def __rememberGameMode(self):
        currentCycleID = self.getCurrentCycleID()
        rememberedCycleID = AccountSettings.getSettings(
            FUN_RANDOM_LAST_CYCLE_ID)
        if currentCycleID is not None and currentCycleID != rememberedCycleID:
            AccountSettings.setSettings(FUN_RANDOM_LAST_CYCLE_ID,
                                        currentCycleID)
            SelectorBattleTypesUtils.setBattleTypeAsUnknown(
                SELECTOR_BATTLE_TYPES.FUN_RANDOM)
        return
class AbstractContextMenuHandler(object):
    __metaclass__ = ABCMeta

    def __init__(self, cmProxy, ctx=None, handlers=None):
        self._eManager = EventManager()
        self.onContextMenuHide = Event(self._eManager)
        super(AbstractContextMenuHandler, self).__init__()
        self.__cmProxy = weakref.proxy(cmProxy)
        self.__handlers = handlers or {}
        self._initFlashValues(ctx)

    @property
    def app(self):
        return self.__cmProxy.app

    def fini(self):
        self._eManager.clear()
        self.__handlers = None
        self.__cmProxy = None
        self._clearFlashValues()
        return

    def getOptions(self, ctx=None):
        return self._generateOptions(ctx)

    def onOptionSelect(self, optionId):
        if optionId in self.__handlers:
            return getattr(self, self.__handlers[optionId])()
        LOG_WARNING('Unknown context menu option', self, self.__cmProxy,
                    optionId)

    def getCMInfo(self):
        pass

    def _dispatchChanges(self, options):
        if self.__cmProxy is not None:
            self.__cmProxy._onOptionsChanged(options)
        return

    @classmethod
    def _makeItem(cls,
                  optId,
                  optLabel=None,
                  optInitData=None,
                  optSubMenu=None,
                  linkage=None,
                  iconType=''):
        return {
            'id': optId,
            'label': optLabel,
            'iconType': iconType,
            'initData': cls.__makeOptDataDefaults(optInitData),
            'submenu': optSubMenu,
            'linkage': linkage
        }

    def _makeSeparator(self):
        return self._makeItem(_SEPARATOR_ID)

    @abstractmethod
    def _generateOptions(self, ctx=None):
        raise NotImplementedError

    def _initFlashValues(self, ctx):
        pass

    def _clearFlashValues(self):
        pass

    @staticmethod
    def __makeOptDataDefaults(optInitData):
        if optInitData is None:
            return {'visible': True}
        else:
            if 'visible' not in optInitData or optInitData['visible'] is None:
                optInitData['visible'] = True
            return optInitData
예제 #41
0
class TabsContainer(object):
    def __init__(self):
        self.__tabs = {
            TABS_IDS.INVENTORY: InventoryBoostersTab(),
            TABS_IDS.QUESTS: QuestsBoostersTab(),
            TABS_IDS.SHOP: ShopBoostersTab(),
        }
        self.__currentTabIdx = None
        self.__activeBoostersCount = None
        self.__eManager = EventManager()
        self.onTabsUpdate = Event(self.__eManager)
        return

    def init(self):
        self.__activeBoostersCount = len(g_goodiesCache.getBoosters(criteria=REQ_CRITERIA.BOOSTER.ACTIVE).values())
        g_clientUpdateManager.addCallbacks(
            {"goodies": self.__onUpdateBoosters, "shop": self.__onUpdateBoosters, "stats": self.__onStatsChanged}
        )
        g_eventsCache.onSyncCompleted += self.__onQuestsUpdate

    def setCurrentTabIdx(self, currentTabIdx):
        self.__currentTabIdx = currentTabIdx

    @property
    def currentTab(self):
        return self.__tabs[self.__currentTabIdx]

    @property
    def inventoryTab(self):
        return self.__tabs[TABS_IDS.INVENTORY]

    @property
    def shopTab(self):
        return self.__tabs[TABS_IDS.SHOP]

    @property
    def questsTab(self):
        return self.__tabs[TABS_IDS.QUESTS]

    def getTabs(self):
        return self.__tabs

    def setFilters(self, qualities, boosterTypes):
        for tab in self.__tabs.itervalues():
            tab.setFilters(qualities, boosterTypes)

    def getActiveBoostersCount(self):
        return self.__activeBoostersCount

    def fini(self):
        self.__currentTabIdx = None
        self.__eManager.clear()
        g_clientUpdateManager.removeObjectCallbacks(self)
        g_eventsCache.onSyncCompleted -= self.__onQuestsUpdate
        for tab in self.__tabs.itervalues():
            tab.fini()

        self.__tabs.clear()
        self.__activeBoostersCount = None
        return

    def __onUpdateBoosters(self, *args):
        for tab in self.__tabs.itervalues():
            tab.update()

        self.__activeBoostersCount = len(g_goodiesCache.getBoosters(criteria=REQ_CRITERIA.BOOSTER.ACTIVE).values())
        self.onTabsUpdate()

    def __onQuestsUpdate(self, *args):
        self.questsTab.updateQuests()
        self.__onUpdateBoosters()

    def __onStatsChanged(self, stats):
        if "credits" in stats or "gold" in stats:
            self.shopTab.updateBalance()
            self.onTabsUpdate()