class EquipmentsPlugin(common.IntervalPlugin): __slots__ = ('__generator',) def __init__(self, parent): super(EquipmentsPlugin, self).__init__(parent) self.__generator = SequenceIDGenerator() def start(self): super(EquipmentsPlugin, self).start() ctrl = self.sessionProvider.shared.equipments if ctrl is not None: ctrl.onEquipmentMarkerShown += self.__onEquipmentMarkerShown return def stop(self): ctrl = self.sessionProvider.shared.equipments if ctrl is not None: ctrl.onEquipmentMarkerShown -= self.__onEquipmentMarkerShown super(EquipmentsPlugin, self).stop() return def __onEquipmentMarkerShown(self, equipment, position, _, interval): uniqueID = self.__generator.next() marker = equipment.getMarker() if marker in settings.EQ_MARKER_TO_SYMBOL: symbol = settings.EQ_MARKER_TO_SYMBOL[marker] else: LOG_ERROR('Symbol is not found for equipment', equipment) return matrix = minimap_utils.makePositionMatrix(position) model = self._addEntryEx(uniqueID, symbol, _C_NAME.EQUIPMENTS, matrix=matrix, active=True) if model is not None: self._setCallback(uniqueID, int(interval)) return
class EquipmentsPlugin(common.IntervalPlugin): __slots__ = ('__generator',) def __init__(self, parent): super(EquipmentsPlugin, self).__init__(parent) self.__generator = SequenceIDGenerator() def start(self): super(EquipmentsPlugin, self).start() ctrl = g_sessionProvider.shared.equipments if ctrl is not None: ctrl.onEquipmentMarkerShown += self.__onEquipmentMarkerShown return def stop(self): ctrl = g_sessionProvider.shared.equipments if ctrl is not None: ctrl.onEquipmentMarkerShown -= self.__onEquipmentMarkerShown super(EquipmentsPlugin, self).stop() return def __onEquipmentMarkerShown(self, equipment, position, _, interval): uniqueID = self.__generator.next() marker = equipment.getMarker() if marker in settings.EQ_MARKER_TO_SYMBOL: symbol = settings.EQ_MARKER_TO_SYMBOL[marker] else: LOG_ERROR('Symbol is not found for equipment', equipment) return matrix = minimap_utils.makePositionMatrix(position) model = self._addEntryEx(uniqueID, symbol, _C_NAME.EQUIPMENTS, matrix=matrix, active=True) if model is not None: self._setCallback(uniqueID, int(interval)) return
class _SquadInvitationsRecorder(_SquadInvitationsHandler): """ This class wraps _SquadInvitationsHandler in order to record player's actions with dyn squads during replay recording.""" __slots__ = ("__idGen",) def __init__(self, setup): super(_SquadInvitationsRecorder, self).__init__(setup) self.__idGen = SequenceIDGenerator() def send(self, playerID): BattleReplay.g_replayCtrl.serializeCallbackData(_SEND_ACTION_NAME, (self.__idGen.next(), playerID)) super(_SquadInvitationsRecorder, self).send(playerID) def accept(self, playerID): BattleReplay.g_replayCtrl.serializeCallbackData(_ACCEPT_ACTION_NAME, (self.__idGen.next(), playerID)) super(_SquadInvitationsRecorder, self).accept(playerID) def reject(self, playerID): BattleReplay.g_replayCtrl.serializeCallbackData(_REJECT_ACTION_NAME, (self.__idGen.next(), playerID)) super(_SquadInvitationsRecorder, self).reject(playerID)
class _SquadInvitationsRecorder(_SquadInvitationsHandler): __slots__ = ('__idGen', ) def __init__(self, setup): super(_SquadInvitationsRecorder, self).__init__(setup) self.__idGen = SequenceIDGenerator() def send(self, playerID): BattleReplay.g_replayCtrl.serializeCallbackData( _SEND_ACTION_NAME, (self.__idGen.next(), playerID)) super(_SquadInvitationsRecorder, self).send(playerID) def accept(self, playerID): BattleReplay.g_replayCtrl.serializeCallbackData( _ACCEPT_ACTION_NAME, (self.__idGen.next(), playerID)) super(_SquadInvitationsRecorder, self).accept(playerID) def reject(self, playerID): BattleReplay.g_replayCtrl.serializeCallbackData( _REJECT_ACTION_NAME, (self.__idGen.next(), playerID)) super(_SquadInvitationsRecorder, self).reject(playerID)
class _InvitesIDsManager(object): def __init__(self): self.clear() def clear(self): self.__idsGen = SequenceIDGenerator() self.__idsMap = {'inviteIDs': {}, 'clubIDs': {}} def getInviteID(self, clubDbID, userDbID, creationTime): uniqueID = (clubDbID, userDbID, creationTime) if uniqueID not in self.__idsMap['clubIDs']: inviteID, showAt = self.__idsGen.next(), None self.__idsMap['inviteIDs'][inviteID] = uniqueID self.__idsMap['clubIDs'][uniqueID] = (inviteID, showAt) else: inviteID, showAt = self.__idsMap['clubIDs'][uniqueID] return (inviteID, showAt) def setShowTime(self, inviteID, showAt): uniqueID = self.__idsMap['inviteIDs'][inviteID] self.__idsMap['clubIDs'][uniqueID] = (inviteID, showAt)
class _InvitesIDsManager(object): def __init__(self): self.clear() def clear(self): self.__idsGen = SequenceIDGenerator() self.__idsMap = {'inviteIDs': {}, 'clubIDs': {}} def getInviteID(self, clubDbID, userDbID, creationTime): uniqueID = (clubDbID, userDbID, creationTime) if uniqueID not in self.__idsMap['clubIDs']: inviteID, showAt = self.__idsGen.next(), None self.__idsMap['inviteIDs'][inviteID] = uniqueID self.__idsMap['clubIDs'][uniqueID] = (inviteID, showAt) else: inviteID, showAt = self.__idsMap['clubIDs'][uniqueID] return (inviteID, showAt) def setShowTime(self, inviteID, showAt): uniqueID = self.__idsMap['inviteIDs'][inviteID] self.__idsMap['clubIDs'][uniqueID] = (inviteID, showAt)
class XmppPlugin(IProtoPlugin): DISCONNECT_BY_REQUEST = 0 DISCONNECT_AUTHENTICATION = 1 DISCONNECT_OTHER_ERROR = 2 USE_MOCK_DATA = False ALLOWED_ROSTER_ACTIONS = [ USER_ROSTER_ACTION.AddToFriend, USER_ROSTER_ACTION.AddToIgnored, USER_ROSTER_ACTION.RemoveFromFriend, USER_ROSTER_ACTION.RemoveFromIgnored ] def __init__(self): self.__client = BigWorld.XmppClient() self.__currentUser = None self.__xmppRoster = None self.__usersMgr = None self.__model = None self.__bwRoster = None self.__reconnectCount = 0 self.__reconnectCallbackId = None self.__bwConnected = False self.__isEnabled = False self.__idsGen = SequenceIDGenerator() self.__pendingBattleMode = None self.__databaseID = None return @storage_getter('users') def usersStorage(self): return None @property def isConnected(self): """ Shows current XMPP connection status """ if self.__model is not None: return self.__model.isConnected else: return False def logState(self): if self.__isEnabled: if self.__model is not None and self.__model.isConnected: itemsStrList = [ 'XMPP:logState - XMPP is connected. Logging XMPP roster state:' ] itemsStrList.append('Curr.User JID: {0} Status: {1}'.format( self.__currentUser.bareJid, self.__currentUser.getPresenceStr( self.__currentUser.presence))) for jid, item in self.__xmppRoster.items(): itemsStrList.append( 'Contact JID: {0} Status: {1} Name: {2}'.format( jid, item.getPresenceStr(item.presence), item.name)) LOG_DEBUG('\n'.join(itemsStrList)) else: LOG_DEBUG( 'XMPP:logState - XMPP is not connected yet. Try to run your command later' ) else: LOG_DEBUG( 'XMPP:logState - You are not logged in or connection to XMPP is disabled by server settings' ) return def connect(self, scope=None): if scope is not None: self._setBattleMode(scope) if self.isConnected: return else: self.__bwConnected = True self._cancelReconnectCallback() settings = self._getServerSettings() if settings.get('xmpp_enabled', False): self.__isEnabled = bool(int(settings.get('jdCutouts', 0))) if self.__isEnabled: self._subscribeToActions() LOG_DEBUG( 'XMPP:connect - XMPP functionality is enabled. Starting connection to XMPP server' ) if self.__model is None: self.__model = XmppConnectionModel( settings.get('xmpp_host'), settings.get('xmpp_port'), settings.get('xmpp_resource'), False, None, None) else: self.__model = self.__model._replace( host=settings.get('xmpp_host'), port=settings.get('xmpp_port'), resourceName=settings.get('xmpp_resource'), isConnected=False) if self.__model.host is None: raise Exception, 'XMPP: server xmpp_host is not defined' connections = settings.get('xmpp_connections', []) if len(connections) > 0: self.__model = self.__model._replace( connection=random.choice(connections)) else: self.__model = self.__model._replace( connection=(self.__model.host, self.__model.port)) LOG_DEBUG( 'XMPP:connect - no xmpp_connections are passed - using default connection', self.__model.connection) if self.__model.token is None: Account.g_accountRepository and Account.g_accountRepository.onChatTokenReceived.clear( ) Account.g_accountRepository.onChatTokenReceived += self._tokenCallback BigWorld.player().requestChatToken(self.__idsGen.next()) else: LOG_DEBUG( 'XMPP:connect - trying to connect using token from previous connection' ) self._tokenCallback( cPickle.dumps({ 'error': None, 'token': self.__model.token, 'databaseID': self.__databaseID })) else: LOG_DEBUG( 'XMPP:connect - XMPP functionality is disabled. Stopping execution' ) return def disconnect(self): LOG_DEBUG('XMPP:disconnect') if Account.g_accountRepository: Account.g_accountRepository.onChatTokenReceived.clear() self.__bwConnected = False if self.isConnected: self.__client.disconnect() else: self.onDisconnect() def onConnect(self): """ Called after successful connection, encryption setup and authentication. """ LOG_DEBUG('XMPP:onConnect - Successfully connected to XMPP server') self.__model = self.__model._replace(isConnected=True) self.__reconnectCount = 0 self._cancelReconnectCallback() if self.__pendingBattleMode is not None: self._setBattleMode(self.__pendingBattleMode) self.__pendingBattleMode = None self._doRostersSync() return def onDisconnect(self, reason=DISCONNECT_BY_REQUEST, description=None): """ Called if connection is closed or attempt to connect is failed. Additional description (in English) of disconnect reason is given. If description is empty then disconnect was caused by user (i.e. by explicit call to disconnect()). """ LOG_DEBUG('XMPP:onDisconnect - Disconnected', reason, description) self._cancelReconnectCallback() if reason == self.DISCONNECT_AUTHENTICATION: self.__model = self.__model._replace(token=None) if self.__bwConnected: if self.__isEnabled: self.__model = self.__model._replace(isConnected=False) self.__reconnectCount += 1 reconnectDelay = max( random.random() * 2 * self.__reconnectCount, 10.0) self.__reconnectCallbackId = BigWorld.callback( reconnectDelay, self.connect) LOG_DEBUG( 'XMPP:onDisconnect - will try to reconnect in {0} seconds'. format(reconnectDelay), description) else: if self.__isEnabled: self._unsubscribeFromActions() self.__client.xmppHandler = None self.__currentUser = None self.__xmppRoster = None self.__model = None self.__bwRoster = None self.__isEnabled = False self.__reconnectCount = 0 self.__databaseID = None return def onNewRosterItem(self, bareJid, name, groups, subscriptionTo, subscriptionFrom): """ Called when the contact is changed or added. name is custom contact name chosen by user. groups is set of groups (strings) which contact belongs to. subscriptionTo is presence subscription state in direction "contact TO user". One of SUBSCRIPTION_* values is used. subscriptionFrom is presence subscription state in direction "FROM user to contact". Either SUBSCRIPTION_ON or SUBSCRIPTION_OFF is used here. See onSubscribe() event. """ LOG_DEBUG('XMPP:onNewRosterItem - New roster item added', bareJid, name) if self.__bwRoster is not None: if bareJid in self.__bwRoster: self._addToLocalXmppRoster(bareJid, name, groups, subscriptionTo, subscriptionFrom) else: self._doXmppRosterAction(bareJid, USER_ROSTER_ACTION.RemoveFromFriend) else: self._addToLocalXmppRoster(bareJid, name, groups, subscriptionTo, subscriptionFrom) return def onRosterItemRemove(self, bareJid): """ Called when the contact is removed. """ LOG_DEBUG('XMPP:onRosterItemRemove', bareJid) if self.__bwRoster is not None: if bareJid not in self.__bwRoster: self._removeFromLocalXmppRoster(bareJid) else: user = self.__bwRoster[bareJid] action = USER_ROSTER_ACTION.AddToFriend if bool( user.getRoster() & USERS_ROSTER_FRIEND) else USER_ROSTER_ACTION.AddToIgnored self._doXmppRosterAction(bareJid, action, user.getName()) else: self._removeFromLocalXmppRoster(bareJid) return def onNewRosterResource(self, fullJid, priority, status, presence): """ Called when contact resource is changed or added. You should compare fullJid of resource with fullJid of client to determine if this resource change is actually server acknowledgement of user presence change. Exact value of resource priority depends solely on contact's choice. status can be arbitrary text. Resource presence is defined by one of PRESENCE_* values. """ LOG_DEBUG('XMPP:onNewRosterResource', fullJid, priority, status, presence) fullJidParts = fullJid.split('/') if len(fullJidParts) > 1: bareJid, resourceName = fullJidParts[0:2] if fullJid != self.__client.fullJid: if bareJid not in self.__xmppRoster: self.__xmppRoster[bareJid] = RosterItem(bareJid) self.__xmppRoster[bareJid].updateResource( resourceName, priority, status, presence) else: self.__currentUser.updateResource(resourceName, priority, status, presence) def onRosterResourceRemove(self, fullJid): """ Called when contact resource is removed (i.e. contact has gone offline). """ LOG_DEBUG('XMPP:onRosterResourceRemove', fullJid) fullJidParts = fullJid.split('/') if len(fullJidParts) > 1: bareJid, resourceName = fullJidParts[0:2] if fullJid != self.__client.fullJid: if bareJid in self.__xmppRoster: self.__xmppRoster[bareJid].removeResource(resourceName) else: self.__currentUser.removeResource(resourceName) def onSubscribe(self, bareJid, message): """ Called when a contact (from roster or not) asks for subscription to user status updates. Call setSubscribed() or setUnsubscribed() to allow or disallow sending user status updates to the contact. Roster item will be automatically updated by onNewRosterItem event. Note that transition of subscriptionFrom attribute of contact from SUBSCRIPTION_OFF state to SUBSCRIPTION_PENDING state should be done manually in this callback. This event shouldn't be generated if subscriptionFrom is SUBSCRIPTION_ON, however it's possible. """ LOG_DEBUG('XMPP:onSubscribe - Subscription request received', bareJid, message) self.__client.setSubscribed(bareJid) def _subscribeToActions(self): """ Adds subscription to UsersManager events """ self.__usersMgr = g_messengerEvents.users self.__usersMgr.onUsersRosterReceived += self._onRosterReceived self.__usersMgr.onUserRosterChanged += self._onRosterUpdate def _unsubscribeFromActions(self): """ Removes subscription to UsersManager events """ if self.__usersMgr: self.__usersMgr.onUsersRosterReceived -= self._onRosterReceived self.__usersMgr.onUserRosterChanged -= self._onRosterUpdate self.__usersMgr = None return def _getServerSettings(self): """ Gets server setting values """ if self.USE_MOCK_DATA: settings = { 'jdCutouts': 1, 'xmpp_connections': [('jbr-wowpkis11.pershastudia.org', 5222)], 'xmpp_host': 'jbr-wowpkis11.pershastudia.org', 'xmpp_port': 5222, 'xmpp_resource': 'wot', 'xmpp_enabled': True } elif Account.g_accountRepository: settings = Account.g_accountRepository.serverSettings else: settings = {'jdCutouts': 0, 'xmpp_enabled': False} return settings def _tokenCallback(self, data): """ Callback for PlayerAccount.requestChatToken method call """ data = cPickle.loads(data) errorStr = data.get('error', None) if errorStr is None: self.__model = self.__model._replace(token=data.get('token')) self.__databaseID = data.get('databaseID') host, port = self.__model.connection if self.USE_MOCK_DATA: bareJid = '{0}@{1}'.format('admin1', self.__model.host) else: bareJid = '{0}@{1}'.format(self.__databaseID, self.__model.host) fullJid = '{0}/{1}'.format(bareJid, self.__model.resourceName) self.__currentUser = RosterItem( bareJid, 'Self', [], BigWorld.XmppClient.SUBSCRIPTION_OFF, BigWorld.XmppClient.SUBSCRIPTION_OFF) LOG_DEBUG( 'XMPP:_tokenCallback - Token received - connecting to XMPP server', fullJid, self.__model.token, host, port) self.__client.xmppHandler = self self.__xmppRoster = {} self.__client.connect(fullJid, str(self.__model.token), host, port) else: self.onDisconnect() LOG_ERROR( 'XMPP:_tokenCallback - Error while getting XMPP connection token', errorStr) return def _cancelReconnectCallback(self): try: if self.__reconnectCallbackId is not None: BigWorld.cancelCallback(self.__reconnectCallbackId) except: pass finally: self.__reconnectCallbackId = None return def _onRosterReceived(self): """ Listener for UsersManager.onUsersRosterReceived """ self.__bwRoster = {} contacts = self.usersStorage.all() LOG_DEBUG('XMPP:_onRosterReceived - BW rooster received', contacts) for user in contacts: if user.isCurrentPlayer(): continue if self.USE_MOCK_DATA: bareJid = '{0}@{1}'.format('admin2', self.__model.host) else: bareJid = '{0}@{1}'.format(user.getID(), self.__model.host) self.__bwRoster[bareJid] = user self._doRostersSync() def _onRosterUpdate(self, action, user): """ Listener for UsersManager.onUsersRosterUpdate """ if action in self.ALLOWED_ROSTER_ACTIONS: if self.USE_MOCK_DATA: bareJid = '{0}@{1}'.format('admin2', self.__model.host) else: bareJid = '{0}@{1}'.format(user.getID(), self.__model.host) LOG_DEBUG('XMPP:_onRosterUpdate - BW rooster update', action, user) if action in [ USER_ROSTER_ACTION.AddToFriend, USER_ROSTER_ACTION.AddToIgnored ]: self.__bwRoster[bareJid] = user elif bareJid in self.__bwRoster: del self.__bwRoster[bareJid] self._doXmppRosterAction(bareJid, action, user.getName()) def _doRostersSync(self): """ Performs XMPP roster synchronization with BW roster (BW is Master) """ if self.__bwRoster is not None and self.isConnected: bwJidSet = set(self.__bwRoster) xmppJidSet = set(self.__xmppRoster) LOG_DEBUG('XMPP:_doRostersSync - Syncing BW and XMPP rosters') LOG_DEBUG('XMPP:_doRostersSync - BW roster', bwJidSet) LOG_DEBUG('XMPP:_doRostersSync - XMPP roster', xmppJidSet) toRemove = xmppJidSet - bwJidSet toAdd = bwJidSet - xmppJidSet for jid in toRemove: self._doXmppRosterAction(jid, USER_ROSTER_ACTION.RemoveFromFriend) for jid in toAdd: user = self.__bwRoster[jid] action = USER_ROSTER_ACTION.AddToFriend if bool( user.getRoster() & USERS_ROSTER_FRIEND) else USER_ROSTER_ACTION.AddToIgnored self._doXmppRosterAction(jid, action, user.getName()) return def _addToLocalXmppRoster(self, bareJid, name, groups, subscriptionTo, subscriptionFrom): """ Adds new item to local XMPP roster """ if bareJid in self.__xmppRoster: LOG_DEBUG( 'XMPP:_addToLocalXmppRoster - Updating item in local XMPP roster', bareJid, name, groups, subscriptionTo, subscriptionFrom) item = self.__xmppRoster.get(bareJid) item.name, item.groups, item.subscriptionTo, item.subscriptionFrom = ( name, groups, subscriptionTo, subscriptionFrom) else: LOG_DEBUG( 'XMPP:_addToLocalXmppRoster - Adding item to local XMPP roster', bareJid, name, groups, subscriptionTo, subscriptionFrom) self.__xmppRoster[bareJid] = RosterItem(bareJid, name, groups, subscriptionTo, subscriptionFrom) def _removeFromLocalXmppRoster(self, bareJid): """ Removes item from local XMPP roster """ LOG_DEBUG( 'XMPP:_removeFromLocalXmppRoster - Roster item is removed from local XMPP roster', bareJid, self.__xmppRoster[bareJid].name) del self.__xmppRoster[bareJid] def _doXmppRosterAction(self, bareJid, action, userName='******'): """ Triggers needed roster action with XMPP chat server basing on passes action type """ if action in [ USER_ROSTER_ACTION.AddToFriend, USER_ROSTER_ACTION.AddToIgnored ]: LOG_DEBUG( 'XMPP:_doXmppRosterAction - adding user from BW rooster to XMPP roster', bareJid, userName) self.__client.add(bareJid, userName) self.__client.subscribe(bareJid) elif action in [ USER_ROSTER_ACTION.RemoveFromFriend, USER_ROSTER_ACTION.RemoveFromIgnored ]: LOG_DEBUG( 'XMPP:_doXmppRosterAction - user is removed from BW rooster. Removing from XMPP roster', bareJid) self.__client.remove(bareJid) self.__client.unsubscribe(bareJid) def _setBattleMode(self, mode): LOG_DEBUG('XMPP:_setBattleMode', mode) if self.isConnected: self.__client.presence = BigWorld.XmppClient.PRESENCE_DND if mode == MESSENGER_SCOPE.BATTLE else BigWorld.XmppClient.PRESENCE_AVAILABLE else: self.__pendingBattleMode = mode self.onDisconnect()
class InvitesManager(object): __clanInfo = None def __init__(self, loader): self.__loader = loader self._IDGen = SequenceIDGenerator() self._IDMap = {'inviteIDs': {}, 'prbIDs': {}} self.__receivedInvites = {} self.__unreadInvitesCount = 0 self.__eventManager = Event.EventManager() self.__acceptChain = None self.onReceivedInviteListInited = Event.Event(self.__eventManager) self.onReceivedInviteListModified = Event.Event(self.__eventManager) return def __del__(self): LOG_DEBUG('InvitesManager deleted') def init(self): self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED g_messengerEvents.users.onUsersListReceived += self.__me_onUsersListReceived g_playerEvents.onPrebattleInvitesChanged += self.__pe_onPrebattleInvitesChanged g_playerEvents.onPrebattleInvitesStatus += self.__pe_onPrebattleInvitesStatus def fini(self): self.__clearAcceptChain() self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED self.__loader = None g_messengerEvents.users.onUsersListReceived -= self.__me_onUsersListReceived g_playerEvents.onPrebattleInvitesChanged -= self.__pe_onPrebattleInvitesChanged g_playerEvents.onPrebattleInvitesStatus -= self.__pe_onPrebattleInvitesStatus self.clear() return def start(self): if self.__inited & PRB_INVITES_INIT_STEP.STARTED == 0: self.__inited |= PRB_INVITES_INIT_STEP.STARTED if self.__inited == PRB_INVITES_INIT_STEP.INITED: self.onReceivedInviteListInited() def clear(self): self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED self.__receivedInvites.clear() self.__unreadInvitesCount = 0 self._IDMap = {'inviteIDs': {}, 'prbIDs': {}} self.__eventManager.clear() def onAvatarBecomePlayer(self): if self.__inited & PRB_INVITES_INIT_STEP.STARTED > 0: self.__inited ^= PRB_INVITES_INIT_STEP.STARTED self.__clearAcceptChain() @storage_getter('users') def users(self): return None def isInited(self): return self.__inited == PRB_INVITES_INIT_STEP.INITED def acceptInvite(self, inviteID, postActions = None): try: prebattleID, peripheryID = self._IDMap['inviteIDs'][inviteID] except KeyError: LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap) return self.__clearAcceptChain() if not postActions: self._doAccept(prebattleID, peripheryID) else: self.__acceptChain = _AcceptInvitesPostActions(peripheryID, prebattleID, postActions) self.__acceptChain.onStopped += self.__accept_onPostActionsStopped self.__acceptChain.start() if self.__unreadInvitesCount > 0: self.__unreadInvitesCount -= 1 def declineInvite(self, inviteID): try: prebattleID, peripheryID = self._IDMap['inviteIDs'][inviteID] except KeyError: LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap) return BigWorld.player().prb_declineInvite(prebattleID, peripheryID) if self.__unreadInvitesCount > 0: self.__unreadInvitesCount -= 1 def canAcceptInvite(self, invite): result = False if invite.alwaysAvailable is True: result = True elif invite.id in self.__receivedInvites: dispatcher = self.__loader.getDispatcher() if dispatcher: prbFunctional = dispatcher.getPrbFunctional() unitFunctional = dispatcher.getUnitFunctional() preQueueFunctional = dispatcher.getPreQueueFunctional() if invite.alreadyJoined: return False if prbFunctional and prbFunctional.hasLockedState() or unitFunctional and unitFunctional.hasLockedState() or preQueueFunctional and preQueueFunctional.hasLockedState(): return False another = invite.anotherPeriphery if another: if g_preDefinedHosts.periphery(invite.peripheryID) is None: LOG_ERROR('Periphery not found') result = False elif g_lobbyContext.getCredentials() is None: LOG_ERROR('Login info not found') result = False elif g_preDefinedHosts.isRoamingPeriphery(invite.peripheryID) and not isRoamingEnabled(g_itemsCache.items.stats.attributes): LOG_ERROR('Roaming is not supported') result = False else: result = invite.id > 0 and invite.isActive() else: result = invite.id > 0 and invite.isActive() return result def canDeclineInvite(self, invite): result = False if invite.id in self.__receivedInvites: result = invite.id > 0 and invite.isActive() return result def getInviteInfo(self, inviteID): try: prebattleID, peripheryID = self._IDMap['inviteIDs'][inviteID] return (prebattleID, peripheryID) except KeyError: return (0, 0) def getReceivedInviteCount(self): return len(self.__receivedInvites) def getReceivedInvite(self, inviteID): invite = None if inviteID in self.__receivedInvites: invite = self.__receivedInvites[inviteID] return invite def getReceivedInvites(self, IDs = None): result = self.__receivedInvites.values() if IDs is not None: result = filter(lambda item: item.id in IDs, result) return result def getUnreadCount(self): return self.__unreadInvitesCount def resetUnreadCount(self): self.__unreadInvitesCount = 0 def _doAccept(self, prebattleID, peripheryID): if connectionManager.peripheryID == peripheryID: BigWorld.player().prb_acceptInvite(prebattleID, peripheryID) else: LOG_ERROR('Invalid periphery', (prebattleID, peripheryID), connectionManager.peripheryID) def _makeInviteID(self, prebattleID, peripheryID): inviteID = self._IDMap['prbIDs'].get((prebattleID, peripheryID)) if inviteID is None: inviteID = self._IDGen.next() self._IDMap['inviteIDs'][inviteID] = (prebattleID, peripheryID) self._IDMap['prbIDs'][prebattleID, peripheryID] = inviteID return inviteID def _addInvite(self, invite, userGetter): if self._isSenderIgnored(invite, userGetter): return False self.__receivedInvites[invite.id] = invite if invite.isActive(): self.__unreadInvitesCount += 1 return True def _updateInvite(self, other, userGetter): inviteID = other.id invite = self.__receivedInvites[inviteID] if self._isSenderIgnored(invite, userGetter): return False prevCount = invite.count invite = invite._merge(other) self.__receivedInvites[inviteID] = invite if invite.isActive() and prevCount < invite.count: self.__unreadInvitesCount += 1 return True def _delInvite(self, inviteID): result = inviteID in self.__receivedInvites if result: self.__receivedInvites.pop(inviteID) return result def _isSenderIgnored(self, invite, userGetter): user = userGetter(invite.creatorDBID) areFriendsOnly = g_settings.userPrefs.invitesFromFriendsOnly if user: if areFriendsOnly: if user.isFriend(): return False else: LOG_DEBUG('Invite is ignored, shows invites from friends only', invite) return True if user.isIgnored(): LOG_DEBUG('Invite is ignored, there is the contact in ignore list', invite, user) return True elif areFriendsOnly: LOG_DEBUG('Invite is ignored, shows invites from friends only', invite) return areFriendsOnly def _buildReceivedInvitesList(self, invitesData): if self.__inited & PRB_INVITES_INIT_STEP.DATA_BUILD == 0: self.__inited |= PRB_INVITES_INIT_STEP.DATA_BUILD self.__receivedInvites.clear() self.__unreadInvitesCount = 0 receiver = getattr(BigWorld.player(), 'name', '') receiverDBID = getPlayerDatabaseID() receiverClanAbbrev = g_lobbyContext.getClanAbbrev(self.__clanInfo) userGetter = self.users.getUser for (prebattleID, peripheryID), data in invitesData.iteritems(): inviteID = self._makeInviteID(prebattleID, peripheryID) invite = PrbInviteWrapper(id=inviteID, receiver=receiver, receiverDBID=receiverDBID, receiverClanAbbrev=receiverClanAbbrev, peripheryID=peripheryID, prebattleID=prebattleID, **data) self._addInvite(invite, userGetter) def __initReceivedInvites(self): step = PRB_INVITES_INIT_STEP.CONTACTS_RECEIVED if self.__inited & step != step: return invitesData = getattr(BigWorld.player(), 'prebattleInvites', {}) LOG_DEBUG('Users roster received, list of invites are available', invitesData) self._buildReceivedInvitesList(invitesData) if self.__inited == PRB_INVITES_INIT_STEP.INITED: self.onReceivedInviteListInited() def __clearAcceptChain(self): if self.__acceptChain is not None: self.__acceptChain.onStopped -= self.__accept_onPostActionsStopped self.__acceptChain.stop() self.__acceptChain = None return def __me_onUsersListReceived(self, tags): doInit = False if USER_TAG.FRIEND in tags: doInit = True step = PRB_INVITES_INIT_STEP.FRIEND_RECEIVED if self.__inited & step == 0: self.__inited |= step if USER_TAG.IGNORED in tags: doInit = True step = PRB_INVITES_INIT_STEP.IGNORED_RECEIVED if self.__inited & step == 0: self.__inited |= step if doInit: self.__initReceivedInvites() def __pe_onPrebattleInvitesChanged(self, diff): step = PRB_INVITES_INIT_STEP.CONTACTS_RECEIVED if self.__inited & step != step: LOG_DEBUG('Received invites are ignored. Manager waits for client will receive contacts') return else: prbInvites = diff.get(('prebattleInvites', '_r')) if prbInvites is not None: self._buildReceivedInvitesList(prbInvites) prbInvites = diff.get('prebattleInvites') if prbInvites is not None: self.__updatePrebattleInvites(prbInvites) return def __pe_onPrebattleInvitesStatus(self, dbID, name, status): if status != PREBATTLE_INVITE_STATUS.OK: statusName = PREBATTLE_INVITE_STATUS_NAMES[status] SystemMessages.pushI18nMessage('#system_messages:invite/status/%s' % statusName, name=name, type=SystemMessages.SM_TYPE.Warning) def __updatePrebattleInvites(self, prbInvites): receiver = BigWorld.player().name receiverDBID = getPlayerDatabaseID() receiverClanAbbrev = g_lobbyContext.getClanAbbrev(self.__clanInfo) added = [] changed = [] deleted = [] modified = False rosterGetter = self.users.getUser for (prebattleID, peripheryID), data in prbInvites.iteritems(): inviteID = self._makeInviteID(prebattleID, peripheryID) if data is None: if self._delInvite(inviteID): modified = True deleted.append(inviteID) continue invite = PrbInviteWrapper(id=inviteID, receiver=receiver, receiverDBID=receiverDBID, receiverClanAbbrev=receiverClanAbbrev, peripheryID=peripheryID, prebattleID=prebattleID, **data) inList = inviteID in self.__receivedInvites if not inList: if self._addInvite(invite, rosterGetter): modified = True added.append(inviteID) elif self._updateInvite(invite, rosterGetter): modified = True changed.append(inviteID) if modified: self.onReceivedInviteListModified(added, changed, deleted) return def __accept_onPostActionsStopped(self, isCompleted): if not isCompleted: return prebattleID = self.__acceptChain.prebattleID peripheryID = self.__acceptChain.peripheryID if (prebattleID, peripheryID) in self._IDMap['prbIDs']: self._doAccept(prebattleID, peripheryID) if self.__unreadInvitesCount > 0: self.__unreadInvitesCount -= 1 else: LOG_ERROR('Prebattle invite not found', prebattleID, peripheryID)
class ClientChat(object): __dataProcessors = [ '_ClientChat__dataTimeProcessor', '_ClientChat__inviteDataTimeProcessor', '_ClientChat__systemMessageTimeProcessor' ] __actionHandlers = { CHAT_ACTIONS.receiveInvite.index(): '_ClientChat__onReceiveInvite' } def __init__(self): raise isinstance(self, BigWorld.Entity) or AssertionError self.__chatActionCallbacks = {} self._idGen = SequenceIDGenerator() def acquireRequestID(self): return self._idGen.next() def requestSystemChatChannels(self): self.__baseChatCommand(CHAT_COMMANDS.requestSystemChatChannels) def findChatChannels(self, sample, requestID=None): if requestID is None: requestID = self.acquireRequestID() try: self.__baseChatCommand(CHAT_COMMANDS.findChatChannels, stringArg1=sample, ignoreCooldown=False, requestID=requestID) except ChatError as ex: self._processChatError(CHAT_ACTIONS.requestChannels, 0, ex, requestID=requestID) return def getChannelInfoById(self, channelId): self.__baseChatCommand(CHAT_COMMANDS.getChannelInfoById, int64Arg=channelId) def requestChatChannelMembers(self, channelId): self.__baseChannelChatCommand(channelId, CHAT_COMMANDS.requestChatChannelMembers) def requestChatChannelMembersCount(self, channelId): self.__baseChannelChatCommand(channelId, CHAT_COMMANDS.getMembersCount) def createChatChannel(self, channelName, password=None): try: self.__baseChatCommand( CHAT_COMMANDS.createChatChannel, stringArg1=channelName, stringArg2=password if password is not None else '', ignoreCooldown=False) except ChatError as ex: self._processChatError(CHAT_COMMANDS.createChatChannel, 0, ex) return def destroyChatChannel(self, channelId): self.__baseChannelChatCommand(channelId, CHAT_COMMANDS.destroyChatChannel) def enterChat(self, channelId, password=None): self.__baseChannelChatCommand( channelId, CHAT_COMMANDS.enterChatChannel, stringArg1=password if password is not None else '') return def broadcast(self, channelId, message): if not len(message) or message.isspace(): return message = message.rstrip() if not isCommandMessage(message): try: self.__baseChannelChatCommand(channelId, CHAT_COMMANDS.broadcast, stringArg1=message, ignoreCooldown=False) except ChatError as ex: self._processChatError(CHAT_ACTIONS.broadcast, channelId, ex) else: try: command, int64Arg, int16Arg, stringArg1, stringArg2 = parseCommandMessage( message) self.__baseChannelChatCommand(channelId, command, int64Arg, int16Arg, stringArg1, stringArg2, ignoreCooldown=False) except ChatCommandError as ex: self._processChatError(CHAT_ACTIONS.userChatCommand, channelId, ex) def leaveChat(self, channelId): self.__baseChannelChatCommand(channelId, CHAT_COMMANDS.leaveChatChannel) def onChatActionFailure(self, actionData): MessengerEntry.g_instance.protos.BW.onChatActionFailure(actionData) def onChatAction(self, chatActionData): global g_replayCtrl if g_replayCtrl is None: import BattleReplay g_replayCtrl = BattleReplay.g_replayCtrl if g_replayCtrl.isRecording: g_replayCtrl.cancelSaveCurrMessage() elif g_replayCtrl.isPlaying: g_replayCtrl.onChatAction(chatActionData) return for processor in self.__dataProcessors: getattr(self, processor)(chatActionData) if CHAT_RESPONSES[ chatActionData['actionResponse']] != CHAT_RESPONSES.success: self.onChatActionFailure(chatActionData) else: hanlerName = self.__actionHandlers.get(chatActionData['action'], None) if hanlerName: getattr(self, hanlerName)(chatActionData) chId = chatActionData['channel'] commonCallbacks = self.__getChatActionCallbacks( CHAT_ACTIONS[chatActionData['action']], 0) commonCallbacks(chatActionData) if chId != 0: channelCallbacks = self.__getChatActionCallbacks( CHAT_ACTIONS[chatActionData['action']], chId) channelCallbacks(chatActionData) return def requestLastSysMessages(self): self.__baseChatCommand(CHAT_COMMANDS.requestLastSysMessages) def findUsers(self, userNamePattern, onlineMode=None, requestID=None): if onlineMode is None: searchMode = USER_SEARCH_MODE.ALL elif onlineMode: searchMode = USER_SEARCH_MODE.ONLINE else: searchMode = USER_SEARCH_MODE.OFFLINE self.__baseChatCommand(CHAT_COMMANDS.findUser, int16Arg=searchMode, stringArg1=userNamePattern, requestID=requestID) return def requestUsersRoster(self, flags=0): self.__baseChatCommand(CHAT_COMMANDS.requestUsersRoster, int16Arg=flags) def logVivoxLogin(self): self.__baseChatCommand(CHAT_COMMANDS.logVivoxLogin) def requestFriendStatus(self, friendID=-1): self.__baseChatCommand(CHAT_COMMANDS.requestFriendStatus, int64Arg=friendID) def addFriend(self, friendID, friendName): self.__baseChatCommand(CHAT_COMMANDS.addFriend, int64Arg=friendID, stringArg1=friendName) def createPrivate(self, friendID, friendName): self.__baseChatCommand(CHAT_COMMANDS.createPrivate, int64Arg=friendID, stringArg1=friendName) def removeFriend(self, friendID): self.__baseChatCommand(CHAT_COMMANDS.removeFriend, int64Arg=friendID) def addIgnored(self, ignoredID, ignoredName): self.__baseChatCommand(CHAT_COMMANDS.addIgnored, int64Arg=ignoredID, stringArg1=ignoredName) def removeIgnored(self, ignoredID): self.__baseChatCommand(CHAT_COMMANDS.removeIgnored, int64Arg=ignoredID) def setMuted(self, mutedID, mutedName): self.__baseChatCommand(CHAT_COMMANDS.setMuted, int64Arg=mutedID, stringArg1=mutedName) def unsetMuted(self, mutedID): self.__baseChatCommand(CHAT_COMMANDS.unsetMuted, int64Arg=mutedID) def createPrebattleInvite(self, receiverName, auxText, prebattleID, prebattleType, requestID=None): self.__baseInviteCommand(CHAT_COMMANDS.createInvite, INVITE_TYPES.PREBATTLE, receiverName, prebattleID, prebattleType, stringArg2=auxText, requestID=requestID) def createBarterInvite(self, receiverName, auxText, itemID, requestID=None): self.__baseInviteCommand(CHAT_COMMANDS.createInvite, INVITE_TYPES.BARTER, receiverName, itemID, stringArg2=auxText, requestID=requestID) def acceptPrebattleInvite(self, inviteID, requestID=None): if requestID is None: requestID = self.acquireRequestID() self.base.ackCommand(requestID, CHAT_COMMANDS.acceptInvite.index(), time.time(), inviteID, -1) return def rejectInvite(self, inviteID, requestID=None): if requestID is None: requestID = self.acquireRequestID() self.base.ackCommand(requestID, CHAT_COMMANDS.rejectInvite.index(), time.time(), inviteID, -1) return def getActiveInvites(self): self.__baseInviteCommand(CHAT_COMMANDS.getActiveInvites) def getArchiveInvites(self): self.__baseInviteCommand(CHAT_COMMANDS.getArchiveInvites) def requestVOIPCredentials(self, changePwd=0): self.__baseChatCommand(CHAT_COMMANDS.requestVOIPCredentials, int16Arg=changePwd) def subscribeChatAction(self, callback, action, channelId=None): cbs = self.__getChatActionCallbacks(action, channelId) cbs += callback def unsubscribeChatAction(self, callback, action, channelId=None): cbs = self.__getChatActionCallbacks(action, channelId) cbs -= callback def setChatActionsCallbacks(self, callbacks): self.__chatActionCallbacks = callbacks def sendChannelChatCommand(self, channelID, command, int64Arg=0, int16Arg=0, stringArg1='', stringArg2=''): self.__baseChannelChatCommand(channelID, command, int64Arg, int16Arg, stringArg1, stringArg2) def _processChatError(self, action, channelId, chatError, requestID=-1): if isinstance(chatError, ChatError): actionData = chatError.messageArgs if chatError.messageArgs is not None else chatError.message else: actionData = '' chatAction = buildChatActionData( action=action, requestID=requestID, channelId=channelId, originatorNickName=self.name, data=actionData, actionResponse=chatError.response if isinstance( chatError, ChatError) else CHAT_RESPONSES.internalError) self.onChatAction(chatAction) return def __getChatActionCallbacks(self, action, channelId): channelId = channelId if channelId is not None else 0 key = (action, channelId) if key not in self.__chatActionCallbacks: handlers = self.__chatActionCallbacks[key] = Event.Event() else: handlers = self.__chatActionCallbacks[key] return handlers def __receiveStreamedData(self, streamID, data): failed = False try: data = zlib.decompress(data) chatMessages = cPickle.loads(data) except: LOG_CURRENT_EXCEPTION() failed = True if not failed: chIds = sorted(chatMessages.keys(), cmp=lambda x, y: cmp(abs(x), abs(y))) for chId in chIds: channelQueue = chatMessages.get(chId, deque()) while True: try: actionData = channelQueue.popleft() self.onChatAction(actionData) except IndexError: break self.__baseChatCommand(CHAT_COMMANDS.initAck, int64Arg=streamID, int16Arg=failed) def __baseChannelChatCommand(self, channelID, command, int64Arg=0, int16Arg=0, stringArg1='', stringArg2='', ignoreCooldown=True): if 0 == channelID: LOG_ERROR('Can`t execute chat channel command for channelId: %s' % (channelID, )) else: if chat_shared.isOperationInCooldown( chat_shared.g_chatCooldownData, command): if ignoreCooldown: return raise ChatCommandInCooldown(command) self.__baseChatCommand(command, channelID, int64Arg, int16Arg, stringArg1, stringArg2) def __baseChatCommand(self, command, channelID=0, int64Arg=0, int16Arg=0, stringArg1='', stringArg2='', ignoreCooldown=True, requestID=None): if requestID is None: requestID = self.acquireRequestID() if chat_shared.isOperationInCooldown(chat_shared.g_chatCooldownData, command): if not ignoreCooldown: raise ChatCommandInCooldown(command) self.base.chatCommandFromClient(requestID, command.index(), channelID, int64Arg, int16Arg, stringArg1, stringArg2) return def __baseInviteCommand(self, command, inviteType=None, receiverName='', int64Arg=0, int16Arg=0, stringArg1='', stringArg2='', requestID=None): if requestID is None: requestID = self.acquireRequestID() self.base.inviteCommand( requestID, command.index(), inviteType.index() if inviteType is not None else -1, receiverName, int64Arg, int16Arg, stringArg1, stringArg2) return def __onReceiveInvite(self, chatActionData): inviteID = chatActionData['data'].get('id', None) receivedAt = chatActionData['data'].get('received_at', None) if inviteID is not None and receivedAt is None: requestID = self.acquireRequestID() self.base.ackCommand(requestID, CHAT_COMMANDS.inviteReceived.index(), time.time(), inviteID, -1) return def __dataTimeProcessor(self, actionData): actionData['time'] = tm.makeLocalServerTime(actionData['time']) actionData['sentTime'] = tm.makeLocalServerTime(actionData['sentTime']) def __inviteDataTimeProcessor(self, actionData): isInviteAction = CHAT_ACTIONS[actionData['action']] in ( CHAT_ACTIONS.createInvite, CHAT_ACTIONS.receiveInvite, CHAT_ACTIONS.receiveArchiveInvite) if isInviteAction: if actionData.has_key('data'): inviteData = actionData['data'] if 'sent_at' in inviteData: inviteData['sent_at'] = tm.utcToLocalDatetime( tm.makeLocalServerDatetime(inviteData['sent_at'])) if 'received_at' in inviteData: inviteData['received_at'] = tm.utcToLocalDatetime( tm.makeLocalServerDatetime(inviteData['received_at'])) if 'processed_at' in inviteData: inviteData['processed_at'] = tm.utcToLocalDatetime( tm.makeLocalServerDatetime(inviteData['processed_at'])) def __systemMessageTimeProcessor(self, actionData): isSystemMessage = CHAT_ACTIONS[actionData['action']] in ( CHAT_ACTIONS.personalSysMessage, CHAT_ACTIONS.sysMessage) if isSystemMessage: if actionData.has_key('data'): messageData = actionData['data'] messageType = messageData['type'] if 'created_at' in messageData: messageData['created_at'] = tm.makeLocalServerDatetime( messageData['created_at']) if 'finished_at' in messageData: messageData['finished_at'] = tm.makeLocalServerDatetime( messageData['finished_at']) if 'started_at' in messageData: messageData['started_at'] = tm.makeLocalServerDatetime( messageData['started_at']) if messageType == SYS_MESSAGE_TYPE.serverReboot.index(): messageData['data'] = tm.makeLocalServerDatetime( messageData['data']) elif messageType == SYS_MESSAGE_TYPE.battleResults.index(): if 'arenaCreateTime' in messageData['data']: messageData['data'][ 'arenaCreateTime'] = tm.makeLocalServerTime( messageData['data']['arenaCreateTime']) elif messageType == SYS_MESSAGE_TYPE.goldReceived.index(): messageData['data']['date'] = tm.makeLocalServerTime( messageData['data']['date']) elif messageType in ( SYS_MESSAGE_TYPE.accountTypeChanged.index(), SYS_MESSAGE_TYPE.premiumBought.index(), SYS_MESSAGE_TYPE.premiumExtended.index(), SYS_MESSAGE_TYPE.premiumExpired.index()): if 'expiryTime' in messageData['data']: messageData['data'][ 'expiryTime'] = tm.makeLocalServerTime( messageData['data']['expiryTime'])
class ServiceChannelManager(ChatActionsListener): def __init__(self): ChatActionsListener.__init__(self) self.__idGenerator = SequenceIDGenerator() self.__messages = deque([], SCH_MSGS_MAX_LENGTH) self.__unreadMessagesCount = 0 def addListeners(self): self.addListener(self.onReceiveSysMessage, CHAT_ACTIONS.sysMessage) self.addListener(self.onReceivePersonalSysMessage, CHAT_ACTIONS.personalSysMessage) def clear(self): self.__messages.clear() self.__unreadMessagesCount = 0 def switch(self, scope): if scope is MESSENGER_SCOPE.LOBBY: self.requestLastServiceMessages() def requestLastServiceMessages(self): BigWorld.player().requestLastSysMessages() def onReceiveSysMessage(self, chatAction): message = ServiceChannelMessage.fromChatAction(chatAction) self.__addServerMessage(message) def onReceivePersonalSysMessage(self, chatAction): message = ServiceChannelMessage.fromChatAction(chatAction, personal=True) self.__addServerMessage(message) def pushClientSysMessage(self, message, msgType, isAlert=False, priority=None): return self.__addClientMessage( message, SCH_CLIENT_MSG_TYPE.SYS_MSG_TYPE, isAlert=isAlert, auxData=[msgType.name(), priority] ) def pushClientMessage(self, message, msgType, isAlert=False, auxData=None): return self.__addClientMessage(message, msgType, isAlert=isAlert, auxData=auxData) def getReadMessages(self): if self.__unreadMessagesCount > 0: messages = list(self.__messages)[: -self.__unreadMessagesCount] else: messages = self.__messages for clientID, message in messages: yield (clientID, message) def getMessage(self, clientID): mapping = dict(self.__messages) message = (False, None, None) if clientID in mapping: message = mapping[clientID] return message def getUnreadCount(self): return self.__unreadMessagesCount def resetUnreadCount(self): self.__unreadMessagesCount = 0 def handleUnreadMessages(self): if not self.__unreadMessagesCount: return unread = list(self.__messages)[-self.__unreadMessagesCount :] serviceChannel = g_messengerEvents.serviceChannel for clientID, (isServerMsg, formatted, settings) in unread: if isServerMsg: serviceChannel.onServerMessageReceived(clientID, formatted, settings) else: serviceChannel.onClientMessageReceived(clientID, formatted, settings) @process def __addServerMessage(self, message): yield lambda callback: callback(True) formatter = collections_by_type.SERVER_FORMATTERS.get(message.type) serviceChannel = g_messengerEvents.serviceChannel serviceChannel.onChatMessageReceived(self.__idGenerator.next(), message) LOG_DEBUG("Server message received", message, formatter) if formatter: try: if formatter.isAsync(): formatted, settings = yield formatter.format(message) else: formatted, settings = formatter.format(message) except: LOG_CURRENT_EXCEPTION() return if formatted: clientID = self.__idGenerator.next() self.__messages.append((clientID, (True, formatted, settings))) self.__unreadMessagesCount += 1 serviceChannel.onServerMessageReceived(clientID, formatted, settings) customEvent = settings.getCustomEvent() if customEvent is not None: serviceChannel.onCustomMessageDataReceived(clientID, customEvent) elif IS_DEVELOPMENT: LOG_WARNING("Not enough data to format. Action data : ", message) elif IS_DEVELOPMENT: LOG_WARNING("Formatter not found. Action data : ", message) return def __addClientMessage(self, message, msgType, isAlert=False, auxData=None): if auxData is None: auxData = [] clientID = 0 formatter = collections_by_type.CLIENT_FORMATTERS.get(msgType) if formatter: try: formatted, settings = formatter.format(message, auxData) except: LOG_CURRENT_EXCEPTION() return if formatted: clientID = self.__idGenerator.next() if not settings.isAlert: settings.isAlert = isAlert self.__messages.append((clientID, (False, formatted, settings))) self.__unreadMessagesCount += 1 g_messengerEvents.serviceChannel.onClientMessageReceived(clientID, formatted, settings) elif IS_DEVELOPMENT: LOG_WARNING("Not enough data to format. Action data : ", message) elif IS_DEVELOPMENT: LOG_WARNING("Formatter not found:", msgType, message) return clientID
class FortBattlesCache(object): __selectedID = 0 def __init__(self, controller): self.__controller = weakref.proxy(controller) self.__idGen = SequenceIDGenerator() self.__cache = {} self.__idToIndex = {} self.__indexToID = {} self.__selectedUnit = None self.__isRequestInProcess = False return def __del__(self): LOG_DEBUG('Fort battles cache deleted:', self) def clear(self): self.__controller = None self.__cache.clear() self.__idToIndex.clear() self.__indexToID.clear() self.__selectedUnit = None return def start(self): fort = self.__controller.getFort() if fort: fort.onFortBattleChanged += self.__fort_onFortBattleChanged fort.onFortBattleRemoved += self.__fort_onFortBattleRemoved fort.onFortBattleUnitReceived += self.__fort_onFortBattleUnitReceived fort.onEnemyStateChanged += self.__fort_onEnemyStateChanged self.__cache = self.__buildCache() else: LOG_ERROR('Client fort is not found') def stop(self): fort = self.__controller.getFort() if fort: fort.onFortBattleChanged -= self.__fort_onFortBattleChanged fort.onFortBattleRemoved -= self.__fort_onFortBattleRemoved fort.onFortBattleUnitReceived -= self.__fort_onFortBattleUnitReceived fort.onEnemyStateChanged -= self.__fort_onEnemyStateChanged self.clear() @property def isRequestInProcess(self): return self.__isRequestInProcess @classmethod def getSelectedID(cls): return cls.__selectedID def getSelectedIdx(self): return self.__getClientIdx(self.getSelectedID()) def clearSelectedID(self): self.__selectedUnit = None self._setSelectedID(0) return def setSelectedID(self, selectedID): if selectedID not in self.__cache: LOG_WARNING('Item is not found in cache', selectedID) return False else: self.__selectedUnit = None return self._setSelectedID(selectedID) def getItem(self, battleID): try: item, fortBattle = self.__cache[battleID] except KeyError: LOG_ERROR('Item not found in cache', battleID) item = None fortBattle = None return (item, fortBattle) def getUnitByIndex(self, index): unit = None if index in self.__indexToID: battleID = self.__indexToID[index] unit = self.__getUnit(battleID) return unit def getSelectedUnit(self): return self.__getUnit(self.getSelectedID()) def getIterator(self): for item, battleItem in self.__cache.itervalues(): if item.filter(): yield (item, battleItem) @classmethod def _setSelectedID(cls, selectedID): result = False if selectedID != cls.__selectedID: cls.__selectedID = selectedID result = True return result @classmethod def _removeStoredData(cls): cls.__selectedID = (0, 0) def __buildCache(self): cache = {} fort = self.__controller.getFort() if not fort: LOG_WARNING('Client fort is not found') return cache fortBattles = fort.getAttacksAndDefencesIn(timePeriod=2 * time_utils.ONE_WEEK) selectedID = self.getSelectedID() found = False for item in fortBattles: battleID = item.getBattleID() if not found and battleID == selectedID: found = True battleItem = fort.getBattle(battleID) cache[battleID] = (item, battleItem) if not found: self.clearSelectedID() return cache def __updateItem(self, battleID, fort): item = fort.getBattleItemByBattleID(battleID) if item is None: LOG_ERROR('Fort battle is not found', battleID, fort.attacks, fort.defences) return (None, None) else: fortBattle = fort.getBattle(battleID) self.__cache[battleID] = (item, fortBattle) if self.getSelectedID() == battleID: self.__selectedUnit = None return (item, fortBattle) def __requestCallback(self, _): self.__isRequestInProcess = False def __removeItem(self, battleID): result = False if battleID in self.__cache: self.__cache.pop(battleID) result = True if self.getSelectedID() == battleID: self.clearSelectedID() clientIdx = self.__idToIndex.pop(battleID, None) if clientIdx is not None: self.__indexToID.pop(clientIdx, None) return result def __getClientIdx(self, battleID): if battleID == 0: return 0 if battleID not in self.__idToIndex: clientIdx = self.__idGen.next() self.__idToIndex[battleID] = clientIdx self.__indexToID[clientIdx] = battleID else: clientIdx = self.__idToIndex[battleID] return clientIdx def __getUnit(self, battleID): fort = self.__controller.getFort() if not fort: LOG_WARNING('Client fort is not found') return else: isSelected = battleID == self.getSelectedID() if isSelected and self.__selectedUnit is not None: return self.__selectedUnit unit = fort.getFortBattleUnit(battleID) if isSelected: self.__selectedUnit = unit return unit def __fort_onEnemyStateChanged(self, battleID, isReady): fort = self.__controller.getFort() if fort: item, battleItem = self.__updateItem(battleID, fort) if item: self.__controller._listeners.notify('onFortBattleChanged', self, item, battleItem) def __fort_onFortBattleChanged(self, battleID): fort = self.__controller.getFort() if fort: item, battleItem = self.__updateItem(battleID, fort) if item: self.__controller._listeners.notify('onFortBattleChanged', self, item, battleItem) def __fort_onFortBattleRemoved(self, battleID): if self.__removeItem(battleID): self.__controller._listeners.notify('onFortBattleRemoved', self, battleID) def __fort_onFortBattleUnitReceived(self, battleID): fort = self.__controller.getFort() if fort: if self.__selectedID == battleID: self.__selectedUnit = None self.__controller._listeners.notify('onFortBattleUnitReceived', self.__getClientIdx(battleID)) return
class ServiceChannelManager(ChatActionsListener): def __init__(self): ChatActionsListener.__init__(self) self.__idGenerator = SequenceIDGenerator() self.__messages = deque([], SCH_MSGS_MAX_LENGTH) self.__unreadMessagesCount = 0 def addListeners(self): self.addListener(self.onReceiveSysMessage, CHAT_ACTIONS.sysMessage) self.addListener(self.onReceivePersonalSysMessage, CHAT_ACTIONS.personalSysMessage) def clear(self): self.__messages.clear() self.__unreadMessagesCount = 0 def switch(self, scope): if scope is MESSENGER_SCOPE.LOBBY: self.requestLastServiceMessages() def requestLastServiceMessages(self): BigWorld.player().requestLastSysMessages() def onReceiveSysMessage(self, chatAction): message = ServiceChannelMessage.fromChatAction(chatAction) self.__addServerMessage(message) def onReceivePersonalSysMessage(self, chatAction): message = ServiceChannelMessage.fromChatAction(chatAction, personal=True) self.__addServerMessage(message) def pushClientSysMessage(self, message, msgType, isAlert=False, priority=None, messageData=None): return self.__addClientMessage( message, SCH_CLIENT_MSG_TYPE.SYS_MSG_TYPE, isAlert=isAlert, auxData=[msgType.name(), priority, messageData]) def pushClientMessage(self, message, msgType, isAlert=False, auxData=None): return self.__addClientMessage(message, msgType, isAlert=isAlert, auxData=auxData) def getReadMessages(self): if self.__unreadMessagesCount > 0: messages = list(self.__messages)[:-self.__unreadMessagesCount] else: messages = self.__messages for clientID, message in messages: yield (clientID, message) def getMessage(self, clientID): mapping = dict(self.__messages) message = (False, None, None) if clientID in mapping: message = mapping[clientID] return message def getUnreadCount(self): return self.__unreadMessagesCount def resetUnreadCount(self): self.__unreadMessagesCount = 0 def handleUnreadMessages(self): if not self.__unreadMessagesCount: return unread = list(self.__messages)[-self.__unreadMessagesCount:] for clientID, (isServerMsg, formatted, settings) in unread: self._handleUnreadMessage(isServerMsg, clientID, formatted, settings) def _handleUnreadMessage(self, isServerMsg, clientID, formatted, settings): serviceChannel = g_messengerEvents.serviceChannel if isServerMsg: serviceChannel.onServerMessageReceived(clientID, formatted, settings) else: serviceChannel.onClientMessageReceived(clientID, formatted, settings) @process def __addServerMessage(self, message): yield lambda callback: callback(True) formatter = collections_by_type.SERVER_FORMATTERS.get(message.type) serviceChannel = g_messengerEvents.serviceChannel serviceChannel.onChatMessageReceived(self.__idGenerator.next(), message) LOG_DEBUG('Server message received', message, formatter) if formatter: try: if formatter.isAsync(): messagesListData = yield formatter.format(message) else: messagesListData = formatter.format(message) except: LOG_CURRENT_EXCEPTION() return for mData in messagesListData: if mData.data: formatted, settings = mData clientID = self.__idGenerator.next() self.__messages.append( (clientID, (True, formatted, settings))) self.__unreadMessagesCount += 1 serviceChannel.onServerMessageReceived( clientID, formatted, settings) customEvent = settings.getCustomEvent() if customEvent is not None: serviceChannel.onCustomMessageDataReceived( clientID, customEvent) elif not formatter.canBeEmpty() and IS_DEVELOPMENT: LOG_WARNING('Not enough data to format. Action data : ', message) elif IS_DEVELOPMENT: LOG_WARNING('Formatter not found. Action data : ', message) return def __addClientMessage(self, message, msgType, isAlert=False, auxData=None): if auxData is None: auxData = [] clientID = 0 formatter = collections_by_type.CLIENT_FORMATTERS.get(msgType) if formatter: try: messagesListData = formatter.format(message, auxData) except: LOG_CURRENT_EXCEPTION() return for mData in messagesListData: if mData.data: formatted, settings = mData clientID = self.__idGenerator.next() if not settings.isAlert: settings.isAlert = isAlert self.__messages.append( (clientID, (False, formatted, settings))) self.__unreadMessagesCount += 1 g_messengerEvents.serviceChannel.onClientMessageReceived( clientID, formatted, settings) elif IS_DEVELOPMENT: LOG_WARNING('Not enough data to format. Action data : ', message) elif IS_DEVELOPMENT: LOG_WARNING('Formatter not found:', msgType, message) return clientID
class XmppPlugin(IProtoPlugin): DISCONNECT_BY_REQUEST = 0 DISCONNECT_AUTHENTICATION = 1 DISCONNECT_OTHER_ERROR = 2 USE_MOCK_DATA = False ALLOWED_ROSTER_ACTIONS = [USER_ROSTER_ACTION.AddToFriend, USER_ROSTER_ACTION.AddToIgnored, USER_ROSTER_ACTION.RemoveFromFriend, USER_ROSTER_ACTION.RemoveFromIgnored] def __init__(self): self.__client = BigWorld.XmppClient() self.__currentUser = None self.__xmppRoster = None self.__usersMgr = None self.__model = None self.__bwRoster = None self.__reconnectCount = 0 self.__reconnectCallbackId = None self.__bwConnected = False self.__isEnabled = False self.__idsGen = SequenceIDGenerator() self.__pendingBattleMode = None self.__databaseID = None return @storage_getter('users') def usersStorage(self): return None @property def isConnected(self): """ Shows current XMPP connection status """ if self.__model is not None: return self.__model.isConnected else: return False def logState(self): if self.__isEnabled: if self.__model is not None and self.__model.isConnected: itemsStrList = ['XMPP:logState - XMPP is connected. Logging XMPP roster state:'] itemsStrList.append('Curr.User JID: {0} Status: {1}'.format(self.__currentUser.bareJid, self.__currentUser.getPresenceStr(self.__currentUser.presence))) for jid, item in self.__xmppRoster.items(): itemsStrList.append('Contact JID: {0} Status: {1} Name: {2}'.format(jid, item.getPresenceStr(item.presence), item.name)) LOG_DEBUG('\n'.join(itemsStrList)) else: LOG_DEBUG('XMPP:logState - XMPP is not connected yet. Try to run your command later') else: LOG_DEBUG('XMPP:logState - You are not logged in or connection to XMPP is disabled by server settings') return def connect(self, scope = None): if scope is not None: self._setBattleMode(scope) if self.isConnected: return else: self.__bwConnected = True self._cancelReconnectCallback() settings = self._getServerSettings() if settings.get('xmpp_enabled', False): self.__isEnabled = bool(int(settings.get('jdCutouts', 0))) if self.__isEnabled: self._subscribeToActions() LOG_DEBUG('XMPP:connect - XMPP functionality is enabled. Starting connection to XMPP server') if self.__model is None: self.__model = XmppConnectionModel(settings.get('xmpp_host'), settings.get('xmpp_port'), settings.get('xmpp_resource'), False, None, None) else: self.__model = self.__model._replace(host=settings.get('xmpp_host'), port=settings.get('xmpp_port'), resourceName=settings.get('xmpp_resource'), isConnected=False) if self.__model.host is None: raise Exception, 'XMPP: server xmpp_host is not defined' connections = settings.get('xmpp_connections', []) if len(connections) > 0: self.__model = self.__model._replace(connection=random.choice(connections)) else: self.__model = self.__model._replace(connection=(self.__model.host, self.__model.port)) LOG_DEBUG('XMPP:connect - no xmpp_connections are passed - using default connection', self.__model.connection) if self.__model.token is None: Account.g_accountRepository and Account.g_accountRepository.onChatTokenReceived.clear() Account.g_accountRepository.onChatTokenReceived += self._tokenCallback BigWorld.player().requestChatToken(self.__idsGen.next()) else: LOG_DEBUG('XMPP:connect - trying to connect using token from previous connection') self._tokenCallback(cPickle.dumps({'error': None, 'token': self.__model.token, 'databaseID': self.__databaseID})) else: LOG_DEBUG('XMPP:connect - XMPP functionality is disabled. Stopping execution') return def disconnect(self): LOG_DEBUG('XMPP:disconnect') if Account.g_accountRepository: Account.g_accountRepository.onChatTokenReceived.clear() self.__bwConnected = False if self.isConnected: self.__client.disconnect() else: self.onDisconnect() def onConnect(self): """ Called after successful connection, encryption setup and authentication. """ LOG_DEBUG('XMPP:onConnect - Successfully connected to XMPP server') self.__model = self.__model._replace(isConnected=True) self.__reconnectCount = 0 self._cancelReconnectCallback() if self.__pendingBattleMode is not None: self._setBattleMode(self.__pendingBattleMode) self.__pendingBattleMode = None self._doRostersSync() return def onDisconnect(self, reason = DISCONNECT_BY_REQUEST, description = None): """ Called if connection is closed or attempt to connect is failed. Additional description (in English) of disconnect reason is given. If description is empty then disconnect was caused by user (i.e. by explicit call to disconnect()). """ LOG_DEBUG('XMPP:onDisconnect - Disconnected', reason, description) self._cancelReconnectCallback() if reason == self.DISCONNECT_AUTHENTICATION: self.__model = self.__model._replace(token=None) if self.__bwConnected: if self.__isEnabled: self.__model = self.__model._replace(isConnected=False) self.__reconnectCount += 1 reconnectDelay = max(random.random() * 2 * self.__reconnectCount, 10.0) self.__reconnectCallbackId = BigWorld.callback(reconnectDelay, self.connect) LOG_DEBUG('XMPP:onDisconnect - will try to reconnect in {0} seconds'.format(reconnectDelay), description) else: if self.__isEnabled: self._unsubscribeFromActions() self.__client.xmppHandler = None self.__currentUser = None self.__xmppRoster = None self.__model = None self.__bwRoster = None self.__isEnabled = False self.__reconnectCount = 0 self.__databaseID = None return def onNewRosterItem(self, bareJid, name, groups, subscriptionTo, subscriptionFrom): """ Called when the contact is changed or added. name is custom contact name chosen by user. groups is set of groups (strings) which contact belongs to. subscriptionTo is presence subscription state in direction "contact TO user". One of SUBSCRIPTION_* values is used. subscriptionFrom is presence subscription state in direction "FROM user to contact". Either SUBSCRIPTION_ON or SUBSCRIPTION_OFF is used here. See onSubscribe() event. """ LOG_DEBUG('XMPP:onNewRosterItem - New roster item added', bareJid, name) if self.__bwRoster is not None: if bareJid in self.__bwRoster: self._addToLocalXmppRoster(bareJid, name, groups, subscriptionTo, subscriptionFrom) else: self._doXmppRosterAction(bareJid, USER_ROSTER_ACTION.RemoveFromFriend) else: self._addToLocalXmppRoster(bareJid, name, groups, subscriptionTo, subscriptionFrom) return def onRosterItemRemove(self, bareJid): """ Called when the contact is removed. """ LOG_DEBUG('XMPP:onRosterItemRemove', bareJid) if self.__bwRoster is not None: if bareJid not in self.__bwRoster: self._removeFromLocalXmppRoster(bareJid) else: user = self.__bwRoster[bareJid] action = USER_ROSTER_ACTION.AddToFriend if bool(user.getRoster() & USERS_ROSTER_FRIEND) else USER_ROSTER_ACTION.AddToIgnored self._doXmppRosterAction(bareJid, action, user.getName()) else: self._removeFromLocalXmppRoster(bareJid) return def onNewRosterResource(self, fullJid, priority, status, presence): """ Called when contact resource is changed or added. You should compare fullJid of resource with fullJid of client to determine if this resource change is actually server acknowledgement of user presence change. Exact value of resource priority depends solely on contact's choice. status can be arbitrary text. Resource presence is defined by one of PRESENCE_* values. """ LOG_DEBUG('XMPP:onNewRosterResource', fullJid, priority, status, presence) fullJidParts = fullJid.split('/') if len(fullJidParts) > 1: bareJid, resourceName = fullJidParts[0:2] if fullJid != self.__client.fullJid: if bareJid not in self.__xmppRoster: self.__xmppRoster[bareJid] = RosterItem(bareJid) self.__xmppRoster[bareJid].updateResource(resourceName, priority, status, presence) else: self.__currentUser.updateResource(resourceName, priority, status, presence) def onRosterResourceRemove(self, fullJid): """ Called when contact resource is removed (i.e. contact has gone offline). """ LOG_DEBUG('XMPP:onRosterResourceRemove', fullJid) fullJidParts = fullJid.split('/') if len(fullJidParts) > 1: bareJid, resourceName = fullJidParts[0:2] if fullJid != self.__client.fullJid: if bareJid in self.__xmppRoster: self.__xmppRoster[bareJid].removeResource(resourceName) else: self.__currentUser.removeResource(resourceName) def onSubscribe(self, bareJid, message): """ Called when a contact (from roster or not) asks for subscription to user status updates. Call setSubscribed() or setUnsubscribed() to allow or disallow sending user status updates to the contact. Roster item will be automatically updated by onNewRosterItem event. Note that transition of subscriptionFrom attribute of contact from SUBSCRIPTION_OFF state to SUBSCRIPTION_PENDING state should be done manually in this callback. This event shouldn't be generated if subscriptionFrom is SUBSCRIPTION_ON, however it's possible. """ LOG_DEBUG('XMPP:onSubscribe - Subscription request received', bareJid, message) self.__client.setSubscribed(bareJid) def _subscribeToActions(self): """ Adds subscription to UsersManager events """ self.__usersMgr = g_messengerEvents.users self.__usersMgr.onUsersRosterReceived += self._onRosterReceived self.__usersMgr.onUserRosterChanged += self._onRosterUpdate def _unsubscribeFromActions(self): """ Removes subscription to UsersManager events """ if self.__usersMgr: self.__usersMgr.onUsersRosterReceived -= self._onRosterReceived self.__usersMgr.onUserRosterChanged -= self._onRosterUpdate self.__usersMgr = None return def _getServerSettings(self): """ Gets server setting values """ if self.USE_MOCK_DATA: settings = {'jdCutouts': 1, 'xmpp_connections': [('jbr-wowpkis11.pershastudia.org', 5222)], 'xmpp_host': 'jbr-wowpkis11.pershastudia.org', 'xmpp_port': 5222, 'xmpp_resource': 'wot', 'xmpp_enabled': True} elif Account.g_accountRepository: settings = Account.g_accountRepository.serverSettings else: settings = {'jdCutouts': 0, 'xmpp_enabled': False} return settings def _tokenCallback(self, data): """ Callback for PlayerAccount.requestChatToken method call """ data = cPickle.loads(data) errorStr = data.get('error', None) if errorStr is None: self.__model = self.__model._replace(token=data.get('token')) self.__databaseID = data.get('databaseID') host, port = self.__model.connection if self.USE_MOCK_DATA: bareJid = '{0}@{1}'.format('admin1', self.__model.host) else: bareJid = '{0}@{1}'.format(self.__databaseID, self.__model.host) fullJid = '{0}/{1}'.format(bareJid, self.__model.resourceName) self.__currentUser = RosterItem(bareJid, 'Self', [], BigWorld.XmppClient.SUBSCRIPTION_OFF, BigWorld.XmppClient.SUBSCRIPTION_OFF) LOG_DEBUG('XMPP:_tokenCallback - Token received - connecting to XMPP server', fullJid, self.__model.token, host, port) self.__client.xmppHandler = self self.__xmppRoster = {} self.__client.connect(fullJid, str(self.__model.token), host, port) else: self.onDisconnect() LOG_ERROR('XMPP:_tokenCallback - Error while getting XMPP connection token', errorStr) return def _cancelReconnectCallback(self): try: if self.__reconnectCallbackId is not None: BigWorld.cancelCallback(self.__reconnectCallbackId) except: pass finally: self.__reconnectCallbackId = None return def _onRosterReceived(self): """ Listener for UsersManager.onUsersRosterReceived """ self.__bwRoster = {} contacts = self.usersStorage.all() LOG_DEBUG('XMPP:_onRosterReceived - BW rooster received', contacts) for user in contacts: if user.isCurrentPlayer(): continue if self.USE_MOCK_DATA: bareJid = '{0}@{1}'.format('admin2', self.__model.host) else: bareJid = '{0}@{1}'.format(user.getID(), self.__model.host) self.__bwRoster[bareJid] = user self._doRostersSync() def _onRosterUpdate(self, action, user): """ Listener for UsersManager.onUsersRosterUpdate """ if action in self.ALLOWED_ROSTER_ACTIONS: if self.USE_MOCK_DATA: bareJid = '{0}@{1}'.format('admin2', self.__model.host) else: bareJid = '{0}@{1}'.format(user.getID(), self.__model.host) LOG_DEBUG('XMPP:_onRosterUpdate - BW rooster update', action, user) if action in [USER_ROSTER_ACTION.AddToFriend, USER_ROSTER_ACTION.AddToIgnored]: self.__bwRoster[bareJid] = user elif bareJid in self.__bwRoster: del self.__bwRoster[bareJid] self._doXmppRosterAction(bareJid, action, user.getName()) def _doRostersSync(self): """ Performs XMPP roster synchronization with BW roster (BW is Master) """ if self.__bwRoster is not None and self.isConnected: bwJidSet = set(self.__bwRoster) xmppJidSet = set(self.__xmppRoster) LOG_DEBUG('XMPP:_doRostersSync - Syncing BW and XMPP rosters') LOG_DEBUG('XMPP:_doRostersSync - BW roster', bwJidSet) LOG_DEBUG('XMPP:_doRostersSync - XMPP roster', xmppJidSet) toRemove = xmppJidSet - bwJidSet toAdd = bwJidSet - xmppJidSet for jid in toRemove: self._doXmppRosterAction(jid, USER_ROSTER_ACTION.RemoveFromFriend) for jid in toAdd: user = self.__bwRoster[jid] action = USER_ROSTER_ACTION.AddToFriend if bool(user.getRoster() & USERS_ROSTER_FRIEND) else USER_ROSTER_ACTION.AddToIgnored self._doXmppRosterAction(jid, action, user.getName()) return def _addToLocalXmppRoster(self, bareJid, name, groups, subscriptionTo, subscriptionFrom): """ Adds new item to local XMPP roster """ if bareJid in self.__xmppRoster: LOG_DEBUG('XMPP:_addToLocalXmppRoster - Updating item in local XMPP roster', bareJid, name, groups, subscriptionTo, subscriptionFrom) item = self.__xmppRoster.get(bareJid) item.name, item.groups, item.subscriptionTo, item.subscriptionFrom = (name, groups, subscriptionTo, subscriptionFrom) else: LOG_DEBUG('XMPP:_addToLocalXmppRoster - Adding item to local XMPP roster', bareJid, name, groups, subscriptionTo, subscriptionFrom) self.__xmppRoster[bareJid] = RosterItem(bareJid, name, groups, subscriptionTo, subscriptionFrom) def _removeFromLocalXmppRoster(self, bareJid): """ Removes item from local XMPP roster """ LOG_DEBUG('XMPP:_removeFromLocalXmppRoster - Roster item is removed from local XMPP roster', bareJid, self.__xmppRoster[bareJid].name) del self.__xmppRoster[bareJid] def _doXmppRosterAction(self, bareJid, action, userName = '******'): """ Triggers needed roster action with XMPP chat server basing on passes action type """ if action in [USER_ROSTER_ACTION.AddToFriend, USER_ROSTER_ACTION.AddToIgnored]: LOG_DEBUG('XMPP:_doXmppRosterAction - adding user from BW rooster to XMPP roster', bareJid, userName) self.__client.add(bareJid, userName) self.__client.subscribe(bareJid) elif action in [USER_ROSTER_ACTION.RemoveFromFriend, USER_ROSTER_ACTION.RemoveFromIgnored]: LOG_DEBUG('XMPP:_doXmppRosterAction - user is removed from BW rooster. Removing from XMPP roster', bareJid) self.__client.remove(bareJid) self.__client.unsubscribe(bareJid) def _setBattleMode(self, mode): LOG_DEBUG('XMPP:_setBattleMode', mode) if self.isConnected: self.__client.presence = BigWorld.XmppClient.PRESENCE_DND if mode == MESSENGER_SCOPE.BATTLE else BigWorld.XmppClient.PRESENCE_AVAILABLE else: self.__pendingBattleMode = mode self.onDisconnect()
class InvitesManager(object): __clanInfo = None def __init__(self): from gui.prb_control.formatters.invites import PrbInviteLinkFormatter self.__linkFormatter = PrbInviteLinkFormatter() self._IDGen = SequenceIDGenerator() self._IDMap = {'inviteIDs': {}, 'prbIDs': {}} self.__receivedInvites = {} self.__unreadInvitesCount = 0 self.__eventManager = Event.EventManager() self.__acceptChain = None self.onReceivedInviteListInited = Event.Event(self.__eventManager) self.onReceivedInviteListModified = Event.Event(self.__eventManager) return def init(self): self.__isUsersRostersInited = False self.__isInvitesListBuild = False g_messengerEvents.users.onUsersRosterReceived += self.__me_onUsersRosterReceived g_playerEvents.onPrebattleInvitesChanged += self.__pe_onPrebattleInvitesChanged def fini(self): self.__clearAcceptChain() self.__isUsersRostersInited = False self.__isInvitesListBuild = False g_messengerEvents.users.onUsersRosterReceived += self.__me_onUsersRosterReceived g_playerEvents.onPrebattleInvitesChanged -= self.__pe_onPrebattleInvitesChanged self.clear() def clear(self): self.__isUsersRostersInited = False self.__isInvitesListBuild = False self.__receivedInvites.clear() self.__unreadInvitesCount = 0 self._IDMap = {'inviteIDs': {}, 'prbIDs': {}} self.__eventManager.clear() @process def onAccountShowGUI(self): clanInfo = yield StatsRequester().getClanInfo() self._setClanInfo(clanInfo) g_clientUpdateManager.addCallbacks({'stats.clanInfo': self._setClanInfo}) def onAvatarBecomePlayer(self): g_clientUpdateManager.removeObjectCallbacks(self) self.__clearAcceptChain() @storage_getter('users') def users(self): return None def isInited(self): return self.__isUsersRostersInited and self.__isInvitesListBuild def acceptInvite(self, inviteID, postActions = None): try: prebattleID, peripheryID = self._IDMap['inviteIDs'][inviteID] except KeyError: LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap) return self.__clearAcceptChain() if not postActions: self._doAccept(prebattleID, peripheryID) else: self.__acceptChain = _AcceptInvitesPostActions(peripheryID, prebattleID, postActions) self.__acceptChain.onStopped += self.__accept_onPostActionsStopped self.__acceptChain.start() if self.__unreadInvitesCount > 0: self.__unreadInvitesCount -= 1 def declineInvite(self, inviteID): try: prebattleID, peripheryID = self._IDMap['inviteIDs'][inviteID] except KeyError: LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap) return BigWorld.player().prb_declineInvite(prebattleID, peripheryID) if self.__unreadInvitesCount > 0: self.__unreadInvitesCount -= 1 def canAcceptInvite(self, invite): result = False if invite.id in self.__receivedInvites: from gui.prb_control.dispatcher import g_prbLoader dispatcher = g_prbLoader.getDispatcher() if dispatcher: prbFunctional = dispatcher.getPrbFunctional() unitFunctional = dispatcher.getUnitFunctional() return (prbFunctional and prbFunctional.hasLockedState() or unitFunctional and unitFunctional.hasLockedState()) and False another = invite.anotherPeriphery if another: if g_preDefinedHosts.periphery(invite.peripheryID) is None: LOG_ERROR('Periphery not found') result = False elif g_lobbyContext.getCredentials() is None: LOG_ERROR('Login info not found') result = False elif g_preDefinedHosts.isRoamingPeriphery(invite.peripheryID) and not isRoamingEnabled(g_itemsCache.items.stats.attributes): LOG_ERROR('Roaming is not supported') result = False elif invite.id > 0: result = invite.isActive() else: result = invite.id > 0 and invite.isActive() return result def canDeclineInvite(self, invite): result = False if invite.id in self.__receivedInvites: result = invite.id > 0 and invite.isActive() return result def getInviteInfo(self, inviteID): try: prebattleID, peripheryID = self._IDMap['inviteIDs'][inviteID] return (prebattleID, peripheryID) except KeyError: return (0, 0) def getReceivedInviteCount(self): return len(self.__receivedInvites) def getReceivedInvite(self, inviteID): return self.__receivedInvites.get(inviteID) def getReceivedInvites(self, IDs = None): result = self.__receivedInvites.values() if IDs is not None: result = filter(lambda item: item[0].id in IDs, result) return result def getUnreadCount(self): return self.__unreadInvitesCount def resetUnreadCount(self): self.__unreadInvitesCount = 0 def _doAccept(self, prebattleID, peripheryID): if connectionManager.peripheryID == peripheryID: BigWorld.player().prb_acceptInvite(prebattleID, peripheryID) else: LOG_ERROR('Invalid periphery', (prebattleID, peripheryID), connectionManager.peripheryID) def _makeInviteID(self, prebattleID, peripheryID): inviteID = self._IDMap['prbIDs'].get((prebattleID, peripheryID)) if inviteID is None: inviteID = self._IDGen.next() self._IDMap['inviteIDs'][inviteID] = (prebattleID, peripheryID) self._IDMap['prbIDs'][prebattleID, peripheryID] = inviteID return inviteID def _addInvite(self, invite, userGetter): if g_settings.userPrefs.invitesFromFriendsOnly: user = userGetter(invite.creatorDBID) if user is None or not user.isFriend(): LOG_DEBUG('Invite to be ignored:', invite) return False link = self.__linkFormatter.format(invite) if not len(link): if constants.IS_DEVELOPMENT: LOG_WARNING('Formatter not found. Invite data : ', invite) return False else: self.__receivedInvites[invite.id] = (invite, link) if invite.isActive(): self.__unreadInvitesCount += 1 return True def _updateInvite(self, other, userGetter): inviteID = other.id invite, _ = self.__receivedInvites[inviteID] if other.isActive() and g_settings.userPrefs.invitesFromFriendsOnly: user = userGetter(invite.creatorDBID) if user is None or not user.isFriend(): LOG_DEBUG('Invite to be ignored:', invite) return False prevCount = invite.count invite = invite._merge(other) link = self.__linkFormatter.format(invite) self.__receivedInvites[inviteID] = (invite, link) if invite.isActive() and prevCount < invite.count: self.__unreadInvitesCount += 1 return True def _delInvite(self, inviteID): result = inviteID in self.__receivedInvites if result: self.__receivedInvites.pop(inviteID) return result def _buildReceivedInvitesList(self, invitesData): self.__isInvitesListBuild = True self.__receivedInvites.clear() self.__unreadInvitesCount = 0 receiver = BigWorld.player().name receiverDBID = getPlayerDatabaseID() receiverClanAbbrev = g_lobbyContext.getClanAbbrev(self.__clanInfo) userGetter = self.users.getUser for (prebattleID, peripheryID), data in invitesData.iteritems(): inviteID = self._makeInviteID(prebattleID, peripheryID) invite = PrbInviteWrapper(id=inviteID, receiver=receiver, receiverDBID=receiverDBID, receiverClanAbbrev=receiverClanAbbrev, peripheryID=peripheryID, **data) self._addInvite(invite, userGetter) def _setClanInfo(self, clanInfo): self.__clanInfo = clanInfo if not self.__isUsersRostersInited: return receiverClanAbbrev = g_lobbyContext.getClanAbbrev(self.__clanInfo) changed = [] for inviteID, (invite, _) in self.__receivedInvites.iteritems(): if invite.receiverClanAbbrev != receiverClanAbbrev: invite = invite._replace(receiverClanAbbrev=receiverClanAbbrev) link = self.__linkFormatter.format(invite) self.__receivedInvites[inviteID] = (invite, link) changed.append(inviteID) if len(changed) > 0: self.onReceivedInviteListModified([], changed, []) def __clearAcceptChain(self): if self.__acceptChain is not None: self.__acceptChain.onStopped -= self.__accept_onPostActionsStopped self.__acceptChain.stop() self.__acceptChain = None return def __me_onUsersRosterReceived(self): if not self.__isUsersRostersInited: invitesData = getattr(BigWorld.player(), 'prebattleInvites', {}) LOG_DEBUG('Users roster received, list of invites is available', invitesData) self.__isUsersRostersInited = True self._buildReceivedInvitesList(invitesData) self.onReceivedInviteListInited() def __pe_onPrebattleInvitesChanged(self, diff): if not self.__isUsersRostersInited: LOG_DEBUG('Received invites ignored. Manager waits for client will receive a roster list') return else: prbInvites = diff.get(('prebattleInvites', '_r')) if prbInvites is not None: self._buildReceivedInvitesList(prbInvites) prbInvites = diff.get('prebattleInvites') if prbInvites is not None: self.__updatePrebattleInvites(prbInvites) return def __updatePrebattleInvites(self, prbInvites): receiver = BigWorld.player().name receiverDBID = getPlayerDatabaseID() receiverClanAbbrev = g_lobbyContext.getClanAbbrev(self.__clanInfo) added = [] changed = [] deleted = [] modified = False rosterGetter = self.users.getUser for (prebattleID, peripheryID), data in prbInvites.iteritems(): inviteID = self._makeInviteID(prebattleID, peripheryID) if data is None: if self._delInvite(inviteID): modified = True deleted.append(inviteID) continue invite = PrbInviteWrapper(id=inviteID, receiver=receiver, receiverDBID=receiverDBID, receiverClanAbbrev=receiverClanAbbrev, peripheryID=peripheryID, **data) inList = inviteID in self.__receivedInvites if not inList: if self._addInvite(invite, rosterGetter): modified = True added.append(inviteID) elif self._updateInvite(invite, rosterGetter): modified = True changed.append(inviteID) if modified: self.onReceivedInviteListModified(added, changed, deleted) return def __accept_onPostActionsStopped(self, isCompleted): if not isCompleted: return prebattleID = self.__acceptChain.prebattleID peripheryID = self.__acceptChain.peripheryID if (prebattleID, peripheryID) in self._IDMap['prbIDs']: self._doAccept(prebattleID, peripheryID) if self.__unreadInvitesCount > 0: self.__unreadInvitesCount -= 1 else: LOG_ERROR('Prebattle invite not found', prebattleID, peripheryID)
class BrowserController(Controller, AppRef): _BROWSER_TEXTURE = 'BrowserBg' _ALT_BROWSER_TEXTURE = 'AltBrowserBg' def __init__(self, proxy): super(BrowserController, self).__init__(proxy) self.__browsers = {} self.__browsersCallbacks = {} self.__browserIDGenerator = SequenceIDGenerator() self.__eventMgr = Event.EventManager() self.onBrowserAdded = Event.Event(self.__eventMgr) self.onBrowserDeleted = Event.Event(self.__eventMgr) self.__urlMacros = URLMarcos() def fini(self): self.__eventMgr.clear() self.__eventMgr = None self.__urlMacros.clear() self.__urlMacros = None self.__browserIDGenerator = None super(BrowserController, self).fini() return def onBattleStarted(self): self.__stop() def onDisconnected(self): self.__stop() @async @process def load(self, url = None, title = None, showActionBtn = True, showWaiting = True, browserID = None, isAsync = False, browserSize = None, background = None, isDefault = True, callback = None): url = url or GUI_SETTINGS.browser.url suffix = yield self.__urlMacros.parse(GUI_SETTINGS.browser.params) concatenator = '&' if '?' in url else '?' if suffix not in url: url = concatenator.join([url, suffix]) size = browserSize or BROWSER.SIZE background = background or BROWSER.BACKGROUND if browserID not in self.__browsers: browserID = self.__browserIDGenerator.next() texture = self._BROWSER_TEXTURE if isDefault else self._ALT_BROWSER_TEXTURE self.__browsers[browserID] = WebBrowser(browserID, self.app, texture, size, url, backgroundUrl=background) self.onBrowserAdded(browserID) ctx = {'url': url, 'title': title, 'showActionBtn': showActionBtn, 'showWaiting': showWaiting, 'browserID': browserID, 'size': size, 'isDefault': isDefault, 'isAsync': isAsync} def browserCallback(*args): self.__clearCallback(browserID) self.__showBrowser(browserID, ctx) if isAsync: self.__browsersCallbacks[browserID] = (None, browserCallback) self.__browsers[browserID].onLoadEnd += browserCallback else: self.__browsersCallbacks[browserID] = (browserCallback, None) self.__browsers[browserID].onLoadStart += browserCallback callback(browserID) return def getBrowser(self, browserID): return self.__browsers.get(browserID) def delBrowser(self, browserID): if browserID in self.__browsers: browser = self.__browsers.pop(browserID) loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None)) if loadStart is not None: browser.onLoadStart -= loadStart if loadEnd is not None: browser.onLoadEnd -= loadEnd browser.destroy() self.onBrowserDeleted(browserID) return def __stop(self): while self.__browsers: browserID, browser = self.__browsers.popitem() loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None)) if loadStart is not None: browser.onLoadStart -= loadStart if loadEnd is not None: browser.onLoadEnd -= loadEnd browser.destroy() return def __clearCallback(self, browserID): if browserID in self.__browsersCallbacks: loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None)) if loadStart is not None: self.__browsers[browserID].onLoadStart -= loadStart if loadEnd is not None: self.__browsers[browserID].onLoadEnd -= loadEnd return def __showBrowser(self, browserID, ctx): self.app.fireEvent(LoadViewEvent(VIEW_ALIAS.BROWSER_WINDOW, getViewName(VIEW_ALIAS.BROWSER_WINDOW, browserID), ctx=ctx), EVENT_BUS_SCOPE.LOBBY)
class BrowserController(Controller): _BROWSER_TEXTURE = "BrowserBg" _ALT_BROWSER_TEXTURE = "AltBrowserBg" def __init__(self, proxy): super(BrowserController, self).__init__(proxy) self.__browsers = {} self.__browsersCallbacks = {} self.__browserIDGenerator = SequenceIDGenerator() self.__eventMgr = Event.EventManager() self.onBrowserAdded = Event.Event(self.__eventMgr) self.onBrowserDeleted = Event.Event(self.__eventMgr) self.__urlMacros = URLMarcos() def fini(self): self.__eventMgr.clear() self.__eventMgr = None self.__urlMacros.clear() self.__urlMacros = None self.__browserIDGenerator = None super(BrowserController, self).fini() return def onAvatarBecomePlayer(self): self.__stop() def onDisconnected(self): self.__stop() @async @process def load( self, url=None, title=None, showActionBtn=True, showWaiting=True, browserID=None, isAsync=False, browserSize=None, background=None, isDefault=True, callback=None, showCloseBtn=False, ): url = url or GUI_SETTINGS.browser.url suffix = yield self.__urlMacros.parse(GUI_SETTINGS.browser.params) concatenator = "&" if "?" in url else "?" if suffix not in url: url = concatenator.join([url, suffix]) size = browserSize or BROWSER.SIZE background = background or BROWSER.BACKGROUND if browserID is None: browserID = self.__browserIDGenerator.next() if browserID not in self.__browsers: texture = self._BROWSER_TEXTURE if isDefault else self._ALT_BROWSER_TEXTURE app = g_appLoader.getApp() if not app: raise AssertionError("Application can not be None") self.__browsers[browserID] = WebBrowser(browserID, app, texture, size, url, backgroundUrl=background) self.onBrowserAdded(browserID) ctx = { "url": url, "title": title, "showActionBtn": showActionBtn, "showWaiting": showWaiting, "browserID": browserID, "size": size, "isDefault": isDefault, "isAsync": isAsync, "showCloseBtn": showCloseBtn, } def browserCallback(*args): self.__clearCallback(browserID) self.__showBrowser(browserID, ctx) self.__browsersCallbacks[browserID] = isAsync and (None, browserCallback) self.__browsers[browserID].onLoadEnd += browserCallback else: self.__browsersCallbacks[browserID] = (browserCallback, None) self.__browsers[browserID].onLoadStart += browserCallback callback(browserID) return def getBrowser(self, browserID): return self.__browsers.get(browserID) def delBrowser(self, browserID): if browserID in self.__browsers: browser = self.__browsers.pop(browserID) loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None)) if loadStart is not None: browser.onLoadStart -= loadStart if loadEnd is not None: browser.onLoadEnd -= loadEnd browser.destroy() self.onBrowserDeleted(browserID) return def __stop(self): while self.__browsers: browserID, browser = self.__browsers.popitem() loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None)) if loadStart is not None: browser.onLoadStart -= loadStart if loadEnd is not None: browser.onLoadEnd -= loadEnd browser.destroy() return def __clearCallback(self, browserID): if browserID in self.__browsersCallbacks: loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None)) if loadStart is not None: self.__browsers[browserID].onLoadStart -= loadStart if loadEnd is not None: self.__browsers[browserID].onLoadEnd -= loadEnd return def __showBrowser(self, browserID, ctx): g_eventBus.handleEvent( LoadViewEvent(VIEW_ALIAS.BROWSER_WINDOW, getViewName(VIEW_ALIAS.BROWSER_WINDOW, browserID), ctx=ctx), EVENT_BUS_SCOPE.LOBBY, )
def _generateUserName(): global _g_namesGenerator if _g_namesGenerator is None: _g_namesGenerator = SequenceIDGenerator() return '%s %d' % (i18n.makeString(USER_DEFAULT_NAME_PREFIX), _g_namesGenerator.next())
class InvitesManager(object): __clanInfo = None def __init__(self): from gui.prb_control.formatters.invites import PrbInviteLinkFormatter self.__linkFormatter = PrbInviteLinkFormatter() self._IDGen = SequenceIDGenerator() self._IDMap = {'inviteIDs': {}, 'prbIDs': {}} self.__receivedInvites = {} self.__unreadInvitesCount = 0 self.__eventManager = Event.EventManager() self.__acceptChain = None self.onReceivedInviteListInited = Event.Event(self.__eventManager) self.onReceivedInviteListModified = Event.Event(self.__eventManager) return def init(self): self.__isUsersRostersInited = False self.__isInvitesListBuild = False g_messengerEvents.users.onUsersRosterReceived += self.__me_onUsersRosterReceived g_playerEvents.onPrebattleInvitesChanged += self.__pe_onPrebattleInvitesChanged def fini(self): self.__clearAcceptChain() self.__isUsersRostersInited = False self.__isInvitesListBuild = False g_messengerEvents.users.onUsersRosterReceived += self.__me_onUsersRosterReceived g_playerEvents.onPrebattleInvitesChanged -= self.__pe_onPrebattleInvitesChanged self.clear() def clear(self): self.__isUsersRostersInited = False self.__isInvitesListBuild = False self.__receivedInvites.clear() self.__unreadInvitesCount = 0 self._IDMap = {'inviteIDs': {}, 'prbIDs': {}} self.__eventManager.clear() @process def onAccountShowGUI(self): clanInfo = yield StatsRequester().getClanInfo() self._setClanInfo(clanInfo) g_clientUpdateManager.addCallbacks( {'stats.clanInfo': self._setClanInfo}) def onAvatarBecomePlayer(self): g_clientUpdateManager.removeObjectCallbacks(self) self.__clearAcceptChain() @storage_getter('users') def users(self): return None def isInited(self): return self.__isUsersRostersInited and self.__isInvitesListBuild def acceptInvite(self, inviteID, postActions=None): try: prebattleID, peripheryID = self._IDMap['inviteIDs'][inviteID] except KeyError: LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap) return self.__clearAcceptChain() if not postActions: self._doAccept(prebattleID, peripheryID) else: self.__acceptChain = _AcceptInvitesPostActions( peripheryID, prebattleID, postActions) self.__acceptChain.onStopped += self.__accept_onPostActionsStopped self.__acceptChain.start() if self.__unreadInvitesCount > 0: self.__unreadInvitesCount -= 1 def declineInvite(self, inviteID): try: prebattleID, peripheryID = self._IDMap['inviteIDs'][inviteID] except KeyError: LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap) return BigWorld.player().prb_declineInvite(prebattleID, peripheryID) if self.__unreadInvitesCount > 0: self.__unreadInvitesCount -= 1 def canAcceptInvite(self, invite): result = False if invite.id in self.__receivedInvites: from gui.prb_control.dispatcher import g_prbLoader dispatcher = g_prbLoader.getDispatcher() if dispatcher: prbFunctional = dispatcher.getPrbFunctional() unitFunctional = dispatcher.getUnitFunctional() return (prbFunctional and prbFunctional.hasLockedState() or unitFunctional and unitFunctional.hasLockedState()) and False another = invite.anotherPeriphery if another: if g_preDefinedHosts.periphery(invite.peripheryID) is None: LOG_ERROR('Periphery not found') result = False elif g_lobbyContext.getCredentials() is None: LOG_ERROR('Login info not found') result = False elif g_preDefinedHosts.isRoamingPeriphery( invite.peripheryID) and not isRoamingEnabled( g_itemsCache.items.stats.attributes): LOG_ERROR('Roaming is not supported') result = False elif invite.id > 0: result = invite.isActive() else: result = invite.id > 0 and invite.isActive() return result def canDeclineInvite(self, invite): result = False if invite.id in self.__receivedInvites: result = invite.id > 0 and invite.isActive() return result def getInviteInfo(self, inviteID): try: prebattleID, peripheryID = self._IDMap['inviteIDs'][inviteID] return (prebattleID, peripheryID) except KeyError: return (0, 0) def getReceivedInviteCount(self): return len(self.__receivedInvites) def getReceivedInvite(self, inviteID): return self.__receivedInvites.get(inviteID) def getReceivedInvites(self, IDs=None): result = self.__receivedInvites.values() if IDs is not None: result = filter(lambda item: item[0].id in IDs, result) return result def getUnreadCount(self): return self.__unreadInvitesCount def resetUnreadCount(self): self.__unreadInvitesCount = 0 def _doAccept(self, prebattleID, peripheryID): if connectionManager.peripheryID == peripheryID: BigWorld.player().prb_acceptInvite(prebattleID, peripheryID) else: LOG_ERROR('Invalid periphery', (prebattleID, peripheryID), connectionManager.peripheryID) def _makeInviteID(self, prebattleID, peripheryID): inviteID = self._IDMap['prbIDs'].get((prebattleID, peripheryID)) if inviteID is None: inviteID = self._IDGen.next() self._IDMap['inviteIDs'][inviteID] = (prebattleID, peripheryID) self._IDMap['prbIDs'][prebattleID, peripheryID] = inviteID return inviteID def _addInvite(self, invite, userGetter): if g_settings.userPrefs.invitesFromFriendsOnly: user = userGetter(invite.creatorDBID) if user is None or not user.isFriend(): LOG_DEBUG('Invite to be ignored:', invite) return False link = self.__linkFormatter.format(invite) if not len(link): if constants.IS_DEVELOPMENT: LOG_WARNING('Formatter not found. Invite data : ', invite) return False else: self.__receivedInvites[invite.id] = (invite, link) if invite.isActive(): self.__unreadInvitesCount += 1 return True def _updateInvite(self, other, userGetter): inviteID = other.id invite, _ = self.__receivedInvites[inviteID] if other.isActive() and g_settings.userPrefs.invitesFromFriendsOnly: user = userGetter(invite.creatorDBID) if user is None or not user.isFriend(): LOG_DEBUG('Invite to be ignored:', invite) return False prevCount = invite.count invite = invite._merge(other) link = self.__linkFormatter.format(invite) self.__receivedInvites[inviteID] = (invite, link) if invite.isActive() and prevCount < invite.count: self.__unreadInvitesCount += 1 return True def _delInvite(self, inviteID): result = inviteID in self.__receivedInvites if result: self.__receivedInvites.pop(inviteID) return result def _buildReceivedInvitesList(self, invitesData): self.__isInvitesListBuild = True self.__receivedInvites.clear() self.__unreadInvitesCount = 0 receiver = BigWorld.player().name receiverDBID = getPlayerDatabaseID() receiverClanAbbrev = g_lobbyContext.getClanAbbrev(self.__clanInfo) userGetter = self.users.getUser for (prebattleID, peripheryID), data in invitesData.iteritems(): inviteID = self._makeInviteID(prebattleID, peripheryID) invite = PrbInviteWrapper(id=inviteID, receiver=receiver, receiverDBID=receiverDBID, receiverClanAbbrev=receiverClanAbbrev, peripheryID=peripheryID, **data) self._addInvite(invite, userGetter) def _setClanInfo(self, clanInfo): self.__clanInfo = clanInfo if not self.__isUsersRostersInited: return receiverClanAbbrev = g_lobbyContext.getClanAbbrev(self.__clanInfo) changed = [] for inviteID, (invite, _) in self.__receivedInvites.iteritems(): if invite.receiverClanAbbrev != receiverClanAbbrev: invite = invite._replace(receiverClanAbbrev=receiverClanAbbrev) link = self.__linkFormatter.format(invite) self.__receivedInvites[inviteID] = (invite, link) changed.append(inviteID) if len(changed) > 0: self.onReceivedInviteListModified([], changed, []) def __clearAcceptChain(self): if self.__acceptChain is not None: self.__acceptChain.onStopped -= self.__accept_onPostActionsStopped self.__acceptChain.stop() self.__acceptChain = None return def __me_onUsersRosterReceived(self): if not self.__isUsersRostersInited: invitesData = getattr(BigWorld.player(), 'prebattleInvites', {}) LOG_DEBUG('Users roster received, list of invites is available', invitesData) self.__isUsersRostersInited = True self._buildReceivedInvitesList(invitesData) self.onReceivedInviteListInited() def __pe_onPrebattleInvitesChanged(self, diff): if not self.__isUsersRostersInited: LOG_DEBUG( 'Received invites ignored. Manager waits for client will receive a roster list' ) return else: prbInvites = diff.get(('prebattleInvites', '_r')) if prbInvites is not None: self._buildReceivedInvitesList(prbInvites) prbInvites = diff.get('prebattleInvites') if prbInvites is not None: self.__updatePrebattleInvites(prbInvites) return def __updatePrebattleInvites(self, prbInvites): receiver = BigWorld.player().name receiverDBID = getPlayerDatabaseID() receiverClanAbbrev = g_lobbyContext.getClanAbbrev(self.__clanInfo) added = [] changed = [] deleted = [] modified = False rosterGetter = self.users.getUser for (prebattleID, peripheryID), data in prbInvites.iteritems(): inviteID = self._makeInviteID(prebattleID, peripheryID) if data is None: if self._delInvite(inviteID): modified = True deleted.append(inviteID) continue invite = PrbInviteWrapper(id=inviteID, receiver=receiver, receiverDBID=receiverDBID, receiverClanAbbrev=receiverClanAbbrev, peripheryID=peripheryID, **data) inList = inviteID in self.__receivedInvites if not inList: if self._addInvite(invite, rosterGetter): modified = True added.append(inviteID) elif self._updateInvite(invite, rosterGetter): modified = True changed.append(inviteID) if modified: self.onReceivedInviteListModified(added, changed, deleted) return def __accept_onPostActionsStopped(self, isCompleted): if not isCompleted: return prebattleID = self.__acceptChain.prebattleID peripheryID = self.__acceptChain.peripheryID if (prebattleID, peripheryID) in self._IDMap['prbIDs']: self._doAccept(prebattleID, peripheryID) if self.__unreadInvitesCount > 0: self.__unreadInvitesCount -= 1 else: LOG_ERROR('Prebattle invite not found', prebattleID, peripheryID)
class InvitesManager(UsersInfoHelper): __clanInfo = None itemsCache = dependency.descriptor(IItemsCache) sessionProvider = dependency.descriptor(IBattleSessionProvider) settingsCore = dependency.descriptor(ISettingsCore) lobbyContext = dependency.descriptor(ILobbyContext) appLoader = dependency.descriptor(IAppLoader) def __init__(self, loader): super(InvitesManager, self).__init__() self.__loader = loader self._IDGen = SequenceIDGenerator() self._IDMap = {} self.__invites = {} self.__invitesIgnored = {} self.__unreadInvitesCount = 0 self.__eventManager = Event.EventManager() self.__acceptChain = None self.onInvitesListInited = Event.Event(self.__eventManager) self.onReceivedInviteListModified = Event.Event(self.__eventManager) self.onSentInviteListModified = Event.Event(self.__eventManager) self.__isInBattle = False return def __del__(self): _logger.debug('InvitesManager deleted') super(InvitesManager, self).__del__() def init(self): self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED self.settingsCore.onSettingsChanged += self.__onSettingsChanged g_messengerEvents.users.onUsersListReceived += self.__onUsersListReceived g_messengerEvents.users.onUserActionReceived += self.__onUserActionReceived g_messengerEvents.users.onBattleUserActionReceived += self.__onUserActionReceived g_playerEvents.onPrebattleInvitesChanged += self.__onPrebattleInvitesChanged g_playerEvents.onPrebattleInvitationsChanged += self.__onPrebattleInvitationsChanged g_playerEvents.onPrebattleInvitesStatus += self.__onPrebattleInvitesStatus g_eventBus.addListener(events.PrbInvitesEvent.ACCEPT, self.__acceptInvite, scope=EVENT_BUS_SCOPE.LOBBY) def fini(self): self.__clearAcceptChain() self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED self.__loader = None self.settingsCore.onSettingsChanged -= self.__onSettingsChanged g_messengerEvents.users.onUsersListReceived -= self.__onUsersListReceived g_messengerEvents.users.onUserActionReceived -= self.__onUserActionReceived g_messengerEvents.users.onBattleUserActionReceived -= self.__onUserActionReceived g_playerEvents.onPrebattleInvitationsChanged -= self.__onPrebattleInvitationsChanged g_playerEvents.onPrebattleInvitesChanged -= self.__onPrebattleInvitesChanged g_playerEvents.onPrebattleInvitesStatus -= self.__onPrebattleInvitesStatus g_eventBus.removeListener(events.PrbInvitesEvent.ACCEPT, self.__acceptInvite, scope=EVENT_BUS_SCOPE.LOBBY) self.clear() return def start(self): self.__isInBattle = False if self.__inited & PRB_INVITES_INIT_STEP.STARTED == 0: self.__inited |= PRB_INVITES_INIT_STEP.STARTED if self.__inited == PRB_INVITES_INIT_STEP.INITED: self.onInvitesListInited() def clear(self): self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED self.__clearInvites() self._IDMap = {} self.__eventManager.clear() def onAvatarBecomePlayer(self): if self.__inited & PRB_INVITES_INIT_STEP.STARTED == 0: self.__inited |= PRB_INVITES_INIT_STEP.STARTED if self.__inited == PRB_INVITES_INIT_STEP.INITED: self.onInvitesListInited() self.__isInBattle = True self.__clearAcceptChain() @storage_getter('users') def users(self): return None def isInited(self): return self.__inited == PRB_INVITES_INIT_STEP.INITED def acceptInvite(self, inviteID, postActions=None): try: invite = self.__invites[inviteID] except KeyError: _logger.error('Invite ID is invalid. %s', (inviteID, self._IDMap)) return self.__clearAcceptChain() if not postActions: invite.accept() else: self.__acceptChain = _AcceptInvitesPostActions(invite, postActions) self.__acceptChain.onStopped += self.__accept_onPostActionsStopped self.__acceptChain.start() if self.__unreadInvitesCount > 0: self.__unreadInvitesCount -= 1 def declineInvite(self, inviteID): try: invite = self.__invites[inviteID] except KeyError: _logger.error('Invite ID is invalid. %s', (inviteID, self._IDMap)) return invite.decline() if self.__unreadInvitesCount > 0: self.__unreadInvitesCount -= 1 def revokeInvite(self, inviteID): try: invite = self.__invites[inviteID] except KeyError: _logger.error('Invite ID is invalid. %s', (inviteID, self._IDMap)) return invite.revoke() if self.__unreadInvitesCount > 0: self.__unreadInvitesCount -= 1 def canAcceptInvite(self, invite): result = False if invite.alwaysAvailable is True: result = True elif invite.clientID in self.__invites: dispatcher = self.__loader.getDispatcher() if dispatcher: if invite.alreadyJoined: return False if dispatcher.getEntity().hasLockedState(): return False another = invite.anotherPeriphery if another: if g_preDefinedHosts.periphery(invite.peripheryID) is None: _logger.error('Periphery not found') result = False elif self.lobbyContext.getCredentials() is None: _logger.error('Login info not found') result = False elif g_preDefinedHosts.isRoamingPeriphery(invite.peripheryID) and not isRoamingEnabled(self.itemsCache.items.stats.attributes): _logger.error('Roaming is not supported') result = False else: result = invite.clientID > 0 and invite.isActive() else: result = invite.clientID > 0 and invite.isActive() return result def canDeclineInvite(self, invite): result = False if invite.clientID in self.__invites: result = invite.clientID > 0 and invite.isActive() return result def canRevokeInvite(self, invite): result = False if invite.clientID in self.__invites: result = invite.clientID > 0 and invite.isActive() and isCurrentPlayer(invite.creatorID) return result def getInvites(self, incoming=None, version=None, onlyActive=None, withIgnored=False): result = self.__invites.values() if withIgnored: result = chain(result, self.__invitesIgnored.values()) if incoming is not None: result = [ item for item in result if item.isIncoming() is incoming ] if version is not None: result = [ item for item in result if item.getVersion() == version ] if onlyActive is not None: result = [ item for item in result if item.isActive() is onlyActive ] return result def getInvite(self, inviteID): invite = None if inviteID in self.__invites: invite = self.__invites[inviteID] return invite def getReceivedInviteCount(self): return len(self.getReceivedInvites()) def getReceivedInvites(self, ids=None): result = self.getInvites(incoming=True) if ids is not None: result = [ item for item in result if item.clientID in ids ] return result def getSentInvites(self, ids=None): result = self.getInvites(incoming=False) if ids is not None: result = [ item for item in result if item.clientID in ids ] return result def getSentInviteCount(self): return len(self.getSentInvites()) def getUnreadCount(self): return self.__unreadInvitesCount def resetUnreadCount(self): self.__unreadInvitesCount = 0 def onUserNamesReceived(self, names): updated = defaultdict(list) rosterGetter = self.users.getUser inviteMaker = self._getNewInviteMaker(rosterGetter) prebattleInvitations = _getNewInvites() for invite in self.getInvites(version=_InviteVersion.NEW, withIgnored=True): if invite.creatorID in names or invite.receiverID in names: senderID = invite.creatorID if self.appLoader.getSpaceID() == GuiGlobalSpaceID.BATTLE: senderID = invite.creatorVehID inviteUniqueId = UniqueId(id=invite.id, senderID=senderID) inviteData = prebattleInvitations.get(inviteUniqueId) inviteID, invite = inviteMaker(inviteData) if inviteData and self._updateInvite(invite): updated[invite.isIncoming()].append(inviteID) for isIncoming, event in ((True, self.onReceivedInviteListModified), (False, self.onSentInviteListModified)): if updated[isIncoming]: event([], updated[isIncoming], []) def _makeInviteID(self, prebattleID, peripheryID, senderID, receiverID): inviteKey = (prebattleID, peripheryID, senderID, receiverID) inviteID = self._IDMap.get(inviteKey) if inviteID is None: inviteID = self._IDGen.next() self._IDMap[inviteKey] = inviteID return inviteID def _addInvite(self, invite, creator): if self.__isInviteSenderIgnored(invite, creator): self.__invitesIgnored[invite.clientID] = invite return False self.__invites[invite.clientID] = invite if invite.isActive(): self.__unreadInvitesCount += 1 return True def _updateInvite(self, other): inviteID = other.clientID isIgnored = False if inviteID in self.__invites: invite = self.__invites[inviteID] else: isIgnored = True invite = self.__invitesIgnored[inviteID] if invite == other: return False if isIgnored: invite = invite.merge(other) self.__invitesIgnored[inviteID] = invite return False prevCount = invite.count invite = invite.merge(other) self.__invites[inviteID] = invite if invite.isActive() and prevCount < invite.count: self.__unreadInvitesCount += 1 return True def _delInvite(self, inviteID): result = inviteID in self.__invites if result: self.__invites.pop(inviteID) return result def _buildReceivedInvitesList(self, invitesLists): if self.__inited & PRB_INVITES_INIT_STEP.DATA_BUILD == 0: self.__inited |= PRB_INVITES_INIT_STEP.DATA_BUILD self.__clearInvites() for invitesData, maker in invitesLists: for item in invitesData: _, invite = maker(item) if invite: creator = self.users.getUser(invite.creatorID, scope=UserEntityScope.BATTLE if invite.creatorVehID else UserEntityScope.LOBBY) self._addInvite(invite, creator) if self.appLoader.getSpaceID() != GuiGlobalSpaceID.BATTLE: self.syncUsersInfo() def _rebuildInvitesLists(self): rosterGetter = self.users.getUser self._buildReceivedInvitesList([(sorted(_getOldInvites().items(), key=_getOldInviteOrderKey, reverse=False), self._getOldInviteMaker()), (sorted(_getNewInvites().values(), key=operator.itemgetter('sentAt'), reverse=False), self._getNewInviteMaker(rosterGetter))]) def _getOldInviteMaker(self): receiver = getPlayerName() receiverID = getPlayerDatabaseID() receiverClanAbbrev = self.lobbyContext.getClanAbbrev(self.__clanInfo) def _inviteMaker(item): (prebattleID, peripheryID), data = item creatorID = data['creatorDBID'] inviteID = self._makeInviteID(prebattleID, peripheryID, creatorID, receiverID) if data is not None: invite = PrbInviteWrapper(clientID=inviteID, creatorID=creatorID, receiver=receiver, receiverID=receiverID, receiverClanAbbrev=receiverClanAbbrev, peripheryID=peripheryID, prebattleID=prebattleID, **data) else: invite = None return (inviteID, invite) return _inviteMaker def _getNewInviteMaker(self, rosterGetter): def _getUserName(userID, scope): name, abbrev = ('', None) if userID: if self.appLoader.getSpaceID() == GuiGlobalSpaceID.BATTLE: ctx = self.sessionProvider.getCtx() isUserInBattle = ctx.getVehIDBySessionID(userID) != 0 if isUserInBattle: name, abbrev = ctx.getPlayerFullNameParts(avatarSessionID=userID, showVehShortName=False)[1:3] if not name: userName = self.getUserName(userID, scope) userClanAbbrev = self.getUserClanAbbrev(userID) user = rosterGetter(userID, scope=scope) if user and user.hasValidName(): name, abbrev = userName, userClanAbbrev return (name, abbrev) def _inviteMaker(item): peripheryID, prebattleID = PrbInvitationWrapper.getPrbInfo(item.get('info', {})) creatorIDScope = UserEntityScope.LOBBY receiverIDScope = UserEntityScope.LOBBY creatorID = item.get('senderDBID', 0) receiverID = item.get('receiverDBID', 0) if creatorID <= 0: if self.appLoader.getSpaceID() == GuiGlobalSpaceID.BATTLE: ctx = self.sessionProvider.getCtx() if 'senderVehID' in item: creatorID = ctx.getSessionIDByVehID(item['senderVehID']) creatorIDScope = UserEntityScope.BATTLE else: item['senderVehID'] = 0 if receiverID <= 0: if self.appLoader.getSpaceID() == GuiGlobalSpaceID.BATTLE: ctx = self.sessionProvider.getCtx() if 'receiverVehID' in item: receiverID = ctx.getSessionIDByVehID(item['receiverVehID']) receiverIDScope = UserEntityScope.BATTLE else: item['receiverVehID'] = 0 inviteID = self._makeInviteID(prebattleID, peripheryID, creatorID, receiverID) senderName, senderClanAbbrev = _getUserName(creatorID, creatorIDScope) receiverName, receiverClanAbbrev = _getUserName(receiverID, receiverIDScope) return (inviteID, PrbInvitationWrapper(inviteID, creatorID=creatorID, sender=senderName, senderClanAbbrev=senderClanAbbrev, receiverID=receiverID, receiver=receiverName, receiverClanAbbrev=receiverClanAbbrev, **item)) return _inviteMaker def __initReceivedInvites(self): step = PRB_INVITES_INIT_STEP.CONTACTS_RECEIVED if self.__inited & step != step: return self._rebuildInvitesLists() if self.__inited == PRB_INVITES_INIT_STEP.INITED: self.onInvitesListInited() def __clearAcceptChain(self): if self.__acceptChain is not None: self.__acceptChain.onStopped -= self.__accept_onPostActionsStopped self.__acceptChain.stop() self.__acceptChain = None return def __onUsersListReceived(self, tags): doInit = False if USER_TAG.FRIEND in tags: doInit = True step = PRB_INVITES_INIT_STEP.FRIEND_RECEIVED if self.__inited & step == 0: self.__inited |= step if USER_TAG.IGNORED in tags or USER_TAG.IGNORED_TMP in tags: doInit = True step = PRB_INVITES_INIT_STEP.IGNORED_RECEIVED if self.__inited & step == 0: self.__inited |= step if doInit: self.__initReceivedInvites() def __onUserActionReceived(self, actionID, user, *args): if actionID in (USER_ACTION_ID.IGNORED_REMOVED, USER_ACTION_ID.TMP_IGNORED_REMOVED): self.__refreshIgnoredInvitesRemove(user) elif actionID in (USER_ACTION_ID.IGNORED_ADDED, USER_ACTION_ID.TMP_IGNORED_ADDED): self.__refreshIgnoredInvitesAdd(user) elif actionID == USER_ACTION_ID.FRIEND_ADDED: self.__refreshFriendInvitesAdd(user) elif actionID == USER_ACTION_ID.FRIEND_REMOVED: self.__refreshFriendInvitesRemove(user) elif actionID == USER_ACTION_ID.SUBSCRIPTION_CHANGED: if user.isFriend(): self.__refreshFriendInvitesAdd(user) else: self.__refreshFriendInvitesRemove(user) def __onPrebattleInvitesChanged(self, diff): step = PRB_INVITES_INIT_STEP.CONTACTS_RECEIVED if self.__inited & step != step: _logger.debug('Received invites are ignored. Manager waits for client will receive contacts') return if ('prebattleInvites', '_r') in diff: self._rebuildInvitesLists() if 'prebattleInvites' in diff: self.__updateOldPrebattleInvites(_getOldInvites()) def __onPrebattleInvitationsChanged(self, invitations): step = PRB_INVITES_INIT_STEP.CONTACTS_RECEIVED if self.__inited & step != step: _logger.debug('Received invites are ignored. Manager waits for client will receive contacts') return self.__updateNewPrebattleInvites(invitations) @staticmethod def __onPrebattleInvitesStatus(dbID, name, status): if status != PREBATTLE_INVITE_STATUS.OK: statusName = PREBATTLE_INVITE_STATUS_NAMES[status] SystemMessages.pushI18nMessage(backport.text(R.strings.system_messages.invite.status.dyn(statusName)()), name=name, type=SystemMessages.SM_TYPE.Warning) def __updateOldPrebattleInvites(self, prbInvites): added = [] changed = [] deleted = [] modified = False inviteMaker = self._getOldInviteMaker() for item in prbInvites.iteritems(): inviteID, invite = inviteMaker(item) if invite is None: if self._delInvite(inviteID): modified = True deleted.append(inviteID) continue inList = inviteID in self.__invites or inviteID in self.__invitesIgnored if not inList: creator = self.users.getUser(invite.creatorID) if self._addInvite(invite, creator): modified = True added.append(inviteID) if self._updateInvite(invite): modified = True changed.append(inviteID) if modified: self.onReceivedInviteListModified(added, changed, deleted) return def __updateNewPrebattleInvites(self, prbInvites): added = defaultdict(list) changed = defaultdict(list) deleted = defaultdict(list) modified = dict(((v, False) for v in (True, False))) rosterGetter = self.users.getUser inviteMaker = self._getNewInviteMaker(rosterGetter) newInvites = {} for data in sorted(prbInvites.itervalues(), key=operator.itemgetter('sentAt')): inviteID, invite = inviteMaker(data) if self.appLoader.getSpaceID() != GuiGlobalSpaceID.BATTLE and invite.creatorVehID: continue if inviteID not in newInvites or invite.createTime > newInvites[inviteID].createTime: newInvites[inviteID] = invite for invite in self.getInvites(version=_InviteVersion.NEW, withIgnored=True): inviteID = invite.clientID if (self.appLoader.getSpaceID() != GuiGlobalSpaceID.BATTLE and invite.creatorVehID or inviteID not in newInvites) and self._delInvite(inviteID): isIncoming = invite.isIncoming() modified[isIncoming] = True deleted[isIncoming].append(inviteID) for inviteID, invite in newInvites.iteritems(): isIncoming = invite.isIncoming() if inviteID not in self.__invites and inviteID not in self.__invitesIgnored: creator = rosterGetter(invite.creatorID, scope=UserEntityScope.BATTLE if invite.creatorVehID else UserEntityScope.LOBBY) if self._addInvite(invite, creator): modified[isIncoming] = True added[isIncoming].append(inviteID) if self._updateInvite(invite): modified[isIncoming] = True changed[isIncoming].append(inviteID) for isIncoming, event in ((True, self.onReceivedInviteListModified), (False, self.onSentInviteListModified)): if modified[isIncoming]: event(added[isIncoming], changed[isIncoming], deleted[isIncoming]) if self.appLoader.getSpaceID() != GuiGlobalSpaceID.BATTLE: self.syncUsersInfo() def __accept_onPostActionsStopped(self, isCompleted): if not isCompleted: return invite = self.__acceptChain.invite invite.accept() if self.__unreadInvitesCount > 0: self.__unreadInvitesCount -= 1 def __clearInvites(self): self.__invites.clear() self.__invitesIgnored.clear() self.__unreadInvitesCount = 0 def __isInviteSenderIgnored(self, invite, user, friendsSetting=None): if self.__isInBattle and invite.isIncoming(): arenaDP = self.sessionProvider.getArenaDP() if arenaDP and arenaDP.getVehicleInfo().prebattleID > 0: return True friendsOnly = friendsSetting if friendsSetting is not None else g_settings.userPrefs.invitesFromFriendsOnly return isInviteSenderIgnored(user, friendsOnly, invite.isCreatedInBattle()) def __refreshIgnoredInvitesRemove(self, user): invitations = [] for invite in self.__invitesIgnored.itervalues(): if invite.creatorID == user.getID(): invitations.append(invite.clientID) for inviteID in invitations: self.__invites[inviteID] = self.__invitesIgnored.pop(inviteID) self.onReceivedInviteListModified(invitations, [], []) if self.appLoader.getSpaceID() != GuiGlobalSpaceID.BATTLE: self.syncUsersInfo() def __refreshIgnoredInvitesAdd(self, user): invitations = [] for invite in self.__invites.itervalues(): if invite.creatorID == user.getID(): invitations.append(invite.clientID) for inviteID in invitations: self.__invitesIgnored[inviteID] = self.__invites.pop(inviteID) self.onReceivedInviteListModified([], [], invitations) if self.appLoader.getSpaceID() != GuiGlobalSpaceID.BATTLE: self.syncUsersInfo() def __refreshFriendInvitesRemove(self, user): invitations = [] for invite in self.__invites.itervalues(): if invite.creatorID == user.getID() and self.__isInviteSenderIgnored(invite, user): invitations.append(invite.clientID) for inviteID in invitations: self.__invitesIgnored[inviteID] = self.__invites.pop(inviteID) self.onReceivedInviteListModified([], [], invitations) if self.appLoader.getSpaceID() != GuiGlobalSpaceID.BATTLE: self.syncUsersInfo() def __refreshFriendInvitesAdd(self, user): invitations = [] for invite in self.__invitesIgnored.itervalues(): if invite.creatorID == user.getID() and not self.__isInviteSenderIgnored(invite, user): invitations.append(invite.clientID) for inviteID in invitations: self.__invites[inviteID] = self.__invitesIgnored.pop(inviteID) self.onReceivedInviteListModified(invitations, [], []) if self.appLoader.getSpaceID() != GuiGlobalSpaceID.BATTLE: self.syncUsersInfo() def __onSettingsChanged(self, diff): if 'invitesFromFriendsOnly' in diff: invitations = [] isFriends = diff['invitesFromFriendsOnly'] if isFriends: for invite in self.__invites.itervalues(): user = self.users.getUser(invite.creatorID) if self.__isInviteSenderIgnored(invite, user, isFriends): invitations.append(invite.clientID) for inviteID in invitations: self.__invitesIgnored[inviteID] = self.__invites.pop(inviteID) self.onReceivedInviteListModified([], [], invitations) else: for invite in self.__invitesIgnored.itervalues(): user = self.users.getUser(invite.creatorID) if not self.__isInviteSenderIgnored(invite, user, isFriends): invitations.append(invite.clientID) for inviteID in invitations: self.__invites[inviteID] = self.__invitesIgnored.pop(inviteID) self.onReceivedInviteListModified(invitations, [], []) if self.appLoader.getSpaceID() != GuiGlobalSpaceID.BATTLE: self.syncUsersInfo() def __acceptInvite(self, event): self.acceptInvite(event.inviteID, event.postActions)
class BWChatProvider(object): __slots__ = ('__weakref__', '__handlers', '__msgFilters', '__coolDown', '__idGen', '__isEnabled', '__queue') def __init__(self): super(BWChatProvider, self).__init__() self.__handlers = defaultdict(set) self.__msgFilters = None self.__coolDown = _ChatCooldownManager() self.__idGen = SequenceIDGenerator() self.__isEnabled = False self.__queue = [] return def clear(self): self.__handlers.clear() def setEnable(self, value): if self.__isEnabled == value: return self.__isEnabled = value if self.__isEnabled: self.__sendActionsFromQueue() else: self.__queue = [] def doAction(self, actionID, args = None, response = False, skipCoolDown = False): success, reqID = False, 0 if self.__coolDown.isInProcess(actionID): if not skipCoolDown: g_messengerEvents.onErrorReceived(createCoolDownError(actionID)) else: if response: reqID = self.__idGen.next() if self.__isEnabled: success = self.__sendAction(actionID, reqID, args) else: success = self.__addActionToQueue(actionID, reqID, args) return (success, reqID) def onActionReceived(self, actionID, reqID, args): handlers = self.__handlers[actionID] for handler in handlers: try: handler((actionID, reqID), args) except TypeError: LOG_ERROR('Handler has been invoked with error', handler) LOG_CURRENT_EXCEPTION() def setFilters(self, msgFilterChain): self.__msgFilters = msgFilterChain def filterInMessage(self, message): text = self.__msgFilters.chainIn(message.accountDBID, message.text) if not text: result = None else: message.text = text result = message return result def filterOutMessage(self, text, limits): return self.__msgFilters.chainOut(text, limits) def setActionCoolDown(self, actionID, coolDown): self.__coolDown.process(actionID, coolDown) def isActionInCoolDown(self, actionID): return self.__coolDown.isInProcess(actionID) def getActionCoolDown(self, actionID): return self.__coolDown.getTime(actionID) def clearActionCoolDown(self, actionID): self.__coolDown.reset(actionID) def registerHandler(self, actionID, handler): handlers = self.__handlers[actionID] if handler in handlers: LOG_WARNING('Handler already is exist', actionID, handler) else: if not hasattr(handler, '__self__') or not isinstance(handler.__self__, ActionsHandler): LOG_ERROR('Class of handler is not subclass of ActionsHandler', handler) return if callable(handler): handlers.add(handler) else: LOG_ERROR('Handler is invalid', handler) def unregisterHandler(self, actionID, handler): handlers = self.__handlers[actionID] if handler in handlers: handlers.remove(handler) def __sendAction(self, actionID, reqID, args = None): player = BigWorld.player() if player: player.base.messenger_onActionByClient_chat2(actionID, reqID, args or messageArgs()) return True else: LOG_ERROR('Player is not defined') return False def __addActionToQueue(self, actionID, reqID, args = None): self.__queue.append((actionID, reqID, args)) return True def __sendActionsFromQueue(self): invokedIDs = set() while self.__queue: actionID, reqID, args = self.__queue.pop() if actionID in invokedIDs: LOG_WARNING('Action is ignored, your must send action after event "showGUI" is invoked', actionID, reqID, args) continue self.__sendAction(actionID, reqID, args) invokedIDs.add(actionID)
class BWChatProvider(object): __slots__ = ('__weakref__', '__handlers', '__msgFilters', '__coolDown', '__idGen', '__isEnabled', '__queue', '__battleCmdCooldowns', '__replayHelper') def __init__(self): super(BWChatProvider, self).__init__() self.__handlers = defaultdict(set) self.__msgFilters = None self.__coolDown = _ChatCooldownManager() self.__battleCmdCooldowns = [] self.__idGen = SequenceIDGenerator() self.__isEnabled = False self.__queue = [] self.__replayHelper = ChatProviderReplayHelper() return def clear(self): self.__handlers.clear() self.__battleCmdCooldowns = [] self.__replayHelper.onActionReceivedFromReplay -= self.onActionReceived self.__replayHelper.clear() def goToReplay(self): self.__replayHelper.goToReplay() self.__replayHelper.onActionReceivedFromReplay += self.onActionReceived def setEnable(self, value): if self.__isEnabled == value: return self.__isEnabled = value if self.__isEnabled: self.__sendActionsFromQueue() else: self.__queue = [] def doAction(self, actionID, args=None, response=False, skipCoolDown=False): success, reqID = False, 0 if self.__isCooldownInProcess(actionID, args): shouldShowCooldownError = not skipCoolDown and self.__shouldShowErrorMessage(actionID, args) if shouldShowCooldownError: g_messengerEvents.onErrorReceived(createCoolDownError(actionID, self.__getCooldownTime(actionID, args))) else: if response: reqID = self.__idGen.next() if self.__isEnabled: success = self.__sendAction(actionID, reqID, args) else: success = self.__addActionToQueue(actionID, reqID, args) return (success, reqID) def onActionReceived(self, actionID, reqID, args): self.__replayHelper.onActionReceived(actionID, reqID, args) replayCtrl = BattleReplay.g_replayCtrl if replayCtrl.isPlaying and replayCtrl.isServerSideReplay: if self.__skipReplayChat(actionID, reqID, args): return handlers = self.__handlers[actionID] for handler in handlers: try: handler((actionID, reqID), args) except TypeError: LOG_ERROR('Handler has been invoked with error', handler) LOG_CURRENT_EXCEPTION() def setFilters(self, msgFilterChain): self.__msgFilters = msgFilterChain def filterInMessage(self, message): text = message.text senderDBID = message.accountDBID if senderDBID > 0: text = self.__msgFilters.chainIn(senderDBID, text) else: senderAvatarID = message.avatarSessionID if senderAvatarID: text = self.__msgFilters.chainIn(senderAvatarID, text) if not text: result = None else: message.text = text result = message return result def filterOutMessage(self, text, limits): return self.__msgFilters.chainOut(text, limits) def setActionCoolDown(self, actionID, coolDown): self.__coolDown.process(actionID, coolDown) def setBattleActionCoolDown(self, reqID, actionID, targetID=0, cooldownConfig=None): command = _ACTIONS.battleChatCommandFromActionID(actionID) if command and cooldownConfig is not None and command.name not in CHAT_COMMANDS_THAT_IGNORE_COOLDOWNS: currTime = BigWorld.time() addCoolDowns(currTime, self.__battleCmdCooldowns, command.id, command.name, command.cooldownPeriod, targetID, reqID, cooldownConfig) return def isActionInCoolDown(self, actionID): command = _ACTIONS.battleChatCommandFromActionID(actionID) if command: return [ cdData for cdData in self.__battleCmdCooldowns if cdData.cmdID == actionID ] return self.__coolDown.isInProcess(actionID) def getActionCooldownData(self, actionID): command = _ACTIONS.battleChatCommandFromActionID(actionID) if command: return [ cdData for cdData in self.__battleCmdCooldowns if cdData.cmdID == actionID ] return [] def clearActionCoolDown(self, actionID): self.__coolDown.reset(actionID) def clearBattleActionCoolDown(self, requestID, actionID): command = _ACTIONS.battleChatCommandFromActionID(actionID) if command: removeList = [ cdData for cdData in self.__battleCmdCooldowns if cdData.reqID == requestID and cdData.cmdID == command.id ] if removeList: for dataForRemoval in removeList: self.__battleCmdCooldowns.remove(dataForRemoval) def registerHandler(self, actionID, handler): handlers = self.__handlers[actionID] if handler in handlers: LOG_WARNING('Handler already is exist', actionID, handler) else: if not hasattr(handler, '__self__') or not isinstance(handler.__self__, ActionsHandler): LOG_ERROR('Class of handler is not subclass of ActionsHandler', handler) return if callable(handler): handlers.add(handler) else: LOG_ERROR('Handler is invalid', handler) def unregisterHandler(self, actionID, handler): handlers = self.__handlers[actionID] if handler in handlers: handlers.remove(handler) def __sendAction(self, actionID, reqID, args=None): player = BigWorld.player() if not player: LOG_ERROR('Player is not defined') return False player.base.messenger_onActionByClient_chat2(actionID, reqID, args or messageArgs()) return True def __addActionToQueue(self, actionID, reqID, args=None): self.__queue.append((actionID, reqID, args)) return True def __sendActionsFromQueue(self): invokedIDs = set() while self.__queue: actionID, reqID, args = self.__queue.pop() if actionID in invokedIDs: LOG_WARNING('Action is ignored, your must send action after event "showGUI" is invoked', actionID, reqID, args) continue self.__sendAction(actionID, reqID, args) invokedIDs.add(actionID) def __isCooldownInProcess(self, actionID, args=None): command = _ACTIONS.battleChatCommandFromActionID(actionID) if command: currTime = BigWorld.time() targetID = args['int32Arg1'] sndrBlockReason = areSenderCooldownsActive(currTime, self.__battleCmdCooldowns, actionID, targetID) return command.name not in CHAT_COMMANDS_THAT_IGNORE_COOLDOWNS and sndrBlockReason is not None else: return self.__coolDown.isInProcess(actionID) def __getCooldownTime(self, actionID, args=None): command = _ACTIONS.battleChatCommandFromActionID(actionID) if command: currTime = BigWorld.time() targetID = args['int32Arg1'] sndrBlockReason = areSenderCooldownsActive(currTime, self.__battleCmdCooldowns, actionID, targetID) cdTime = round(sndrBlockReason.cooldownEnd - currTime, 1) if sndrBlockReason is not None else 0 return cdTime else: self.__coolDown.getTime(actionID) return def __shouldShowErrorMessage(self, actionID, args=None): command = _ACTIONS.battleChatCommandFromActionID(actionID) if command is None: return False else: currTime = BigWorld.time() targetID = args['int32Arg1'] sndrBlockReason = areSenderCooldownsActive(currTime, self.__battleCmdCooldowns, actionID, targetID) return sndrBlockReason.cooldownType != CHAT_COMMAND_COOLDOWN_TYPE_IDS.TIMEFRAME_DATA_COOLDOWN if sndrBlockReason is not None else False def __skipReplayChat(self, actionID, reqID, args): replayCtrl = BattleReplay.g_replayCtrl reqVehID = args['int64Arg1'] if actionID == _ACTIONS.ON_BATTLE_MESSAGE_BROADCAST and not replayCtrl.isAllyToObservedVehicle(reqVehID): return True else: if _ACTIONS.battleChatCommandFromActionID(actionID) is not None: if _ACTIONS.battleChatCommandFromActionID(actionID).name in (BATTLE_CHAT_COMMAND_NAMES.ATTACKING_ENEMY_WITH_SPG, BATTLE_CHAT_COMMAND_NAMES.ATTACK_ENEMY): if replayCtrl.isAllyToObservedVehicle(reqVehID): return True elif not replayCtrl.isAllyToObservedVehicle(reqVehID): return True return False
class RibbonsAggregator(object): sessionProvider = dependency.descriptor(IBattleSessionProvider) def __init__(self): super(RibbonsAggregator, self).__init__() self.__feedbackProvider = None self.__vehicleStateCtrl = None self.__cache = _RibbonsCache() self.__accumulatedRibbons = _RibbonsCache() self.__rules = {} self.__idGenerator = SequenceIDGenerator() self.onRibbonAdded = Event.Event() self.onRibbonUpdated = Event.Event() self.__isStarted = False self.__isSuspended = False self.__isInPostmortemMode = False return def start(self): self.__isStarted = True if self.__feedbackProvider is None: self.__feedbackProvider = self.sessionProvider.shared.feedback self.__feedbackProvider.onPlayerFeedbackReceived += self._onPlayerFeedbackReceived if self.__vehicleStateCtrl is None: self.__vehicleStateCtrl = self.sessionProvider.shared.vehicleState self.__vehicleStateCtrl.onPostMortemSwitched += self._onPostMortemSwitched self.__vehicleStateCtrl.onRespawnBaseMoving += self.__onRespawnBaseMoving return def suspend(self): if self.__isStarted: self.__isSuspended = True def resume(self): if self.__isSuspended: self.__isSuspended = False def stop(self): self.__isStarted = False self.__isSuspended = False self.clearRibbonsData() if self.__feedbackProvider is not None: self.__feedbackProvider.onPlayerFeedbackReceived -= self._onPlayerFeedbackReceived self.__feedbackProvider = None if self.__vehicleStateCtrl is None: self.__vehicleStateCtrl.onPostMortemSwitched -= self._onPostMortemSwitched self.__vehicleStateCtrl.onRespawnBaseMoving -= self.__onRespawnBaseMoving self.__vehicleStateCtrl = None return def getRibbon(self, ribbonID): """ Gets ribbon by the given ID. :param ribbonID: Ribbon ID. :return: ribbon or None. """ return self.__cache.get(ribbonID, None) def resetRibbonData(self, ribbonID): """ Reset ribbon's data by the given ID. :param ribbonID: ribbon ID """ ribbon = self.__cache.pop(ribbonID) if ribbon is not None and ribbon.getType() in _ACCUMULATED_RIBBON_TYPES: self.__accumulatedRibbons.add(ribbon) return def clearRibbonsData(self): """ Clears all cached ribbons. """ self.__cache.clear() self.__accumulatedRibbons.clear() def _onPostMortemSwitched(self, noRespawnPossible, respawnAvailable): """ Callback on switching to the postmortem mode (see VehicleStateController). """ self.__isInPostmortemMode = True def __onRespawnBaseMoving(self): """ Callback on switching to alive state (see VehicleStateController). """ self.__isInPostmortemMode = False def _onPlayerFeedbackReceived(self, events): """ Callback on player feedback event (see BattleFeedbackAdaptor). :param events: list of PlayerFeedbackEvent """ def _ribbonsGenerator(events): for e in events: r = _createRibbonFromPlayerFeedbackEvent(self.__idGenerator.next(), e) if r is not None: yield r return self._aggregateRibbons(_ribbonsGenerator(events)) def _aggregateRibbons(self, ribbons): """ Aggregates ribbons according to some rules and converts them to appropriate battle efficiency events (see _FEEDBACK_EVENT_TO_RIBBON_CLS). Puts ribbons to the inner cache and triggers appropriate RibbonsAggregator events. Note that knowledge about aggregation is kept in each ribbon type/class (see canAggregate method). :param ribbons: list of Ribbon derived instances """ aggregatedRibbons = {} for ribbon in ribbons: if self.__isSuspended and ribbon.getType() not in _ACCUMULATED_RIBBON_TYPES: continue if ribbon.getType() in aggregatedRibbons: temporaryRibbons = aggregatedRibbons[ribbon.getType()] for temporaryRibbon in temporaryRibbons: if temporaryRibbon.aggregate(ribbon): break else: temporaryRibbons.append(ribbon) else: aggregatedRibbons[ribbon.getType()] = [ribbon] filteredRibbons = self.__filterRibbons(aggregatedRibbons) sortedRibbons = self.__getSortedList(filteredRibbons) for ribbon in sortedRibbons: etype = ribbon.getType() if etype in _NOT_CACHED_RIBBON_TYPES: self.__cache.add(ribbon) self.onRibbonAdded(ribbon) else: for cachedRibbon in self.__cache.iterByType(etype): if cachedRibbon.aggregate(ribbon): if not self.__isSuspended: self.onRibbonUpdated(cachedRibbon) break else: if etype in _ACCUMULATED_RIBBON_TYPES: for accumulatedRibbon in self.__accumulatedRibbons.iterByType(etype): if accumulatedRibbon.aggregate(ribbon): if not self.__isSuspended: self.__accumulatedRibbons.pop(accumulatedRibbon.getID()) self.__cache.add(accumulatedRibbon) self.onRibbonAdded(accumulatedRibbon) break else: if self.__isSuspended: self.__accumulatedRibbons.add(ribbon) else: self.__cache.add(ribbon) self.onRibbonAdded(ribbon) elif not self.__isSuspended: self.__cache.add(ribbon) self.onRibbonAdded(ribbon) def __filterRibbons(self, ribbons): if self.__isInPostmortemMode: for rType in _RIBBON_TYPES_EXCLUDED_IN_POSTMORTEM: if rType in ribbons: del ribbons[rType] if BATTLE_EFFICIENCY_TYPES.DESTRUCTION in ribbons: killRibbons = dict(((r.getVehicleID(), r) for r in ribbons[BATTLE_EFFICIENCY_TYPES.DESTRUCTION])) damageRibbons = dict(((t, ribbons[t]) for t in _RIBBON_TYPES_AGGREGATED_WITH_KILL_RIBBON if t in ribbons)) for rType, tmpRibbons in damageRibbons.iteritems(): filteredRibbons = [] for tmpRibbon in tmpRibbons: if tmpRibbon.getVehicleID() in killRibbons: killRibbon = killRibbons[tmpRibbon.getVehicleID()] killRibbon.setExtraValue(killRibbon.getExtraValue() + tmpRibbon.getExtraValue()) else: filteredRibbons.append(tmpRibbon) ribbons[rType] = filteredRibbons excludedRibbons = dict(((t, ribbons[t]) for t in _RIBBON_TYPES_EXCLUDED_IF_KILL_RIBBON if t in ribbons)) for rType, tmpRibbons in excludedRibbons.iteritems(): filteredRibbons = [ r for r in tmpRibbons if r.getVehicleID() not in killRibbons ] ribbons[rType] = filteredRibbons return ribbons def __getSortedList(self, ribbons): """ Sort events according to the following rules: 1. Enemy kill ribbon should appear at the end of the list. 2. Enemy detection ribbon should appear at the top of the list. NOTE: according to aggregation rules, the output ribbons don't contain duplicates of ribbons with the same type). If there are a few ribbons with the same type in the server response, use the last one. :param ribbons: dict of ribbons to be resorted according to rules described above and converted to the list without duplicates. :return: Sorted ribbons list. """ def _sortKey(ribbon): """ Routine to be used for sorting ribbons by time. Ribbon ID is used for comparing because it grows with time. :param ribbon: _Ribbon derived instance. """ return ribbon.getID() sortedRibons = [] if ribbons: killRibbons = ribbons.pop(BATTLE_EFFICIENCY_TYPES.DESTRUCTION, None) detectionRibbons = ribbons.pop(BATTLE_EFFICIENCY_TYPES.DETECTION, None) if detectionRibbons is not None: sortedRibons.extend(sorted(detectionRibbons, key=_sortKey)) remaningRibbons = [] for newRibbons in ribbons.itervalues(): remaningRibbons.extend(newRibbons) sortedRibons.extend(sorted(remaningRibbons, key=_sortKey)) if killRibbons is not None: sortedRibons.extend(sorted(killRibbons, key=_sortKey)) return sortedRibons
class BWChatProvider(object): def __init__(self): super(BWChatProvider, self).__init__() self.__handlers = defaultdict(set) self.__msgFilters = None self.__coolDown = _ChatCooldownManager() self.__idGen = SequenceIDGenerator() def clear(self): self.__handlers.clear() def doAction(self, actionID, args = None, response = False, skipCoolDown = False): player = BigWorld.player() (success, reqID,) = (False, 0) if player: if self.__coolDown.isInProcess(actionID): if not skipCoolDown: g_messengerEvents.onServerErrorReceived(createCoolDownError(actionID)) elif response: reqID = self.__idGen.next() player.base.messenger_onActionByClient_chat2(actionID, reqID, args or messageArgs()) success = True else: LOG_ERROR('Player is not defined') return (success, reqID) def onActionReceived(self, actionID, reqID, args): handlers = self.__handlers[actionID] for handler in handlers: try: handler((actionID, reqID), args) except TypeError: LOG_ERROR('Handler has been invoked with error', handler) LOG_CURRENT_EXCEPTION() def setFilters(self, msgFilterChain): self.__msgFilters = msgFilterChain def filterInMessage(self, message): text = self.__msgFilters.chainIn(message.accountDBID, message.text) if not text: result = None else: message.text = text result = message return result def filterOutMessage(self, text, limits): return self.__msgFilters.chainOut(text, limits) def setActionCoolDown(self, actionID, coolDown): self.__coolDown.process(actionID, coolDown) def isActionInCoolDown(self, actionID): return self.__coolDown.isInProcess(actionID) def getActionCoolDown(self, actionID): return self.__coolDown.getTime(actionID) def clearActionCoolDown(self, actionID): self.__coolDown.reset(actionID) def registerHandler(self, actionID, handler): handlers = self.__handlers[actionID] if handler in handlers: LOG_WARNING('Handler already is exist', actionID, handler) elif not hasattr(handler, '__self__') or not isinstance(handler.__self__, ActionsHandler): LOG_ERROR('Class of handler is not subclass of ActionsHandler', handler) return if callable(handler): handlers.add(handler) else: LOG_ERROR('Handler is invalid', handler) def unregisterHandler(self, actionID, handler): handlers = self.__handlers[actionID] if handler in handlers: handlers.remove(handler)
class SortiesCache(object): __selectedID = (0, 0) __rosterTypeID = 0 def __init__(self, controller): self.__controller = weakref.proxy(controller) self.__idGen = SequenceIDGenerator() self.__cache = {} self.__idToIndex = {} self.__indexToID = {} self.__selectedUnit = None self.__isRequestInProcess = False self.__cooldownRequest = None return def __del__(self): LOG_DEBUG('Sortie cache deleted:', self) def clear(self): self.__controller = None self.__cache.clear() self.__idToIndex.clear() self.__indexToID.clear() self.__selectedUnit = None if self.__cooldownRequest is not None: BigWorld.cancelCallback(self.__cooldownRequest) self.__cooldownRequest = None return def start(self): fort = self.__controller.getFort() if fort: fort.onSortieChanged += self.__fort_onSortieChanged fort.onSortieRemoved += self.__fort_onSortieRemoved fort.onSortieUnitReceived += self.__fort_onSortieUnitReceived self.__cache = self.__buildCache() else: LOG_ERROR('Client fort is not found') def stop(self): fort = self.__controller.getFort() if fort: fort.onSortieChanged -= self.__fort_onSortieChanged fort.onSortieRemoved -= self.__fort_onSortieRemoved fort.onSortieUnitReceived -= self.__fort_onSortieUnitReceived self.clear() def setController(self, controller): self.__controller = weakref.proxy(controller) @property def isRequestInProcess(self): return self.__isRequestInProcess @classmethod def getSelectedID(cls): return cls.__selectedID def clearSelectedID(self): self.__selectedUnit = None self._setSelectedID((0, 0)) return def setSelectedID(self, selectedID): if selectedID not in self.__cache: LOG_WARNING('Item is not found in cache', selectedID) return False else: self.__selectedUnit = None self._setSelectedID(selectedID) if BigWorld.player().isLongDisconnectedFromCenter: self.__controller._listeners.notify('onSortieUnitReceived', self.__getClientIdx(selectedID)) return True unit = self.getSelectedUnit() if unit and not self.__cache[selectedID]._isDirty: self.__controller._listeners.notify('onSortieUnitReceived', self.__getClientIdx(selectedID)) else: self._requestSortieUnit(selectedID) return True @classmethod def getRosterTypeID(cls): return cls.__rosterTypeID def setRosterTypeID(self, rosterTypeID): result = self._setRosterTypeID(rosterTypeID) if result: self.__cache = self.__buildCache() return result def getItem(self, sortieID): try: item = self.__cache[sortieID] except KeyError: LOG_ERROR('Item not found in cache', sortieID) item = None return item def getUnitByIndex(self, index): unit = None if index in self.__indexToID: sortieID = self.__indexToID[index] unit = self.__getUnit(sortieID) return unit def getSelectedUnit(self): return self.__getUnit(self.getSelectedID()) def getIterator(self): for item in self.__cache.itervalues(): if item.filter(self.__rosterTypeID): yield item def _requestSortieUnit(self, selectedID): Waiting.show('fort/sortie/get') if self.__cooldownRequest is not None: Waiting.hide('fort/sortie/get') BigWorld.cancelCallback(self.__cooldownRequest) self.__cooldownRequest = None ctx = RequestSortieUnitCtx(waitingID='', *selectedID) def requester(): self.__cooldownRequest = None self.__isRequestInProcess = True self.__controller.request(ctx, self.__requestCallback) return if self.__controller._cooldown.isInProcess(ctx.getRequestType()): self.__cooldownRequest = BigWorld.callback(self.__controller._cooldown.getTime(ctx.getRequestType()), requester) else: requester() return @classmethod def _setSelectedID(cls, selectedID): result = False if selectedID != cls.__selectedID and len(selectedID) == 2: cls.__selectedID = selectedID result = True return result @classmethod def _setRosterTypeID(cls, rosterTypeID): result = False if rosterTypeID != cls.__rosterTypeID: cls.__rosterTypeID = rosterTypeID result = True return result @classmethod def _removeStoredData(cls): cls.__selectedID = (0, 0) cls.__rosterTypeID = 0 def __buildCache(self): cache = {} fort = self.__controller.getFort() if not fort: LOG_WARNING('Client fort is not found') return cache sorties = fort.getSorties() selectedID = self.getSelectedID() found = False for sortieID, sortie in sorties.iteritems(): item = SortieItem(sortieID, sortie) if not found and item.getID() == selectedID: found = True cache[sortieID] = item if not found: self.clearSelectedID() return cache def __updateItem(self, sortieID, fort): sortie = fort.getSortieShortData(*sortieID) if sortie is None: LOG_ERROR('Sortie is not found', sortieID, fort.sorties) return else: if sortieID in self.__cache: item = self.__cache[sortieID] item._updateItemData(sortie) if item._isDirty and self.__selectedID == item.getID() and item.filter(self.getRosterTypeID()): self.__selectedUnit = None self._requestSortieUnit(sortieID) else: item = SortieItem(sortieID, sortie) self.__cache[sortieID] = item return item def __requestCallback(self, _): Waiting.hide('fort/sortie/get') self.__isRequestInProcess = False def __removeItem(self, sortieID): result = False if sortieID in self.__cache: self.__cache.pop(sortieID) result = True if self.getSelectedID() == sortieID: self.clearSelectedID() clientIdx = self.__idToIndex.pop(sortieID, None) if clientIdx is not None: self.__indexToID.pop(clientIdx, None) return result def __getClientIdx(self, sortieID): if sortieID == (0, 0): return 0 if sortieID not in self.__idToIndex: clientIdx = self.__idGen.next() self.__idToIndex[sortieID] = clientIdx self.__indexToID[clientIdx] = sortieID else: clientIdx = self.__idToIndex[sortieID] return clientIdx def __getUnit(self, sortieID): fort = self.__controller.getFort() if not fort: LOG_WARNING('Client fort is not found') return else: isSelected = self.getSelectedID() == sortieID if isSelected and self.__selectedUnit is not None: return self.__selectedUnit unit = fort.getSortieUnit(*sortieID) if isSelected: self.__selectedUnit = unit return unit def __fort_onSortieChanged(self, unitMgrID, peripheryID): fort = self.__controller.getFort() sortieID = (unitMgrID, peripheryID) if fort: item = self.__updateItem(sortieID, fort) if item: self.__controller._listeners.notify('onSortieChanged', self, item) def __fort_onSortieRemoved(self, unitMgrID, peripheryID): sortieID = (unitMgrID, peripheryID) if self.__removeItem(sortieID): self.__controller._listeners.notify('onSortieRemoved', self, sortieID) def __fort_onSortieUnitReceived(self, unitMgrID, peripheryID): fort = self.__controller.getFort() sortieID = (unitMgrID, peripheryID) if fort: if unitMgrID in self.__cache: self.__cache[sortieID]._isDirty = False if self.getSelectedID() == sortieID: self.__selectedUnit = None self.__controller._listeners.notify('onSortieUnitReceived', self.__getClientIdx(sortieID)) return
class ClientChat(object): __dataProcessors = ['_ClientChat__dataTimeProcessor', '_ClientChat__inviteDataTimeProcessor', '_ClientChat__systemMessageTimeProcessor'] __actionHandlers = {CHAT_ACTIONS.receiveInvite.index(): '_ClientChat__onReceiveInvite'} def __init__(self): raise isinstance(self, BigWorld.Entity) or AssertionError self.__chatActionCallbacks = {} self._idGen = SequenceIDGenerator() def acquireRequestID(self): return self._idGen.next() def requestSystemChatChannels(self): self.__baseChatCommand(CHAT_COMMANDS.requestSystemChatChannels) def findChatChannels(self, sample, requestID = None): if requestID is None: requestID = self.acquireRequestID() try: self.__baseChatCommand(CHAT_COMMANDS.findChatChannels, stringArg1=sample, ignoreCooldown=False, requestID=requestID) except ChatError as ex: self._processChatError(CHAT_ACTIONS.requestChannels, 0, ex, requestID=requestID) return def getChannelInfoById(self, channelId): self.__baseChatCommand(CHAT_COMMANDS.getChannelInfoById, int64Arg=channelId) def requestChatChannelMembers(self, channelId): self.__baseChannelChatCommand(channelId, CHAT_COMMANDS.requestChatChannelMembers) def requestChatChannelMembersCount(self, channelId): self.__baseChannelChatCommand(channelId, CHAT_COMMANDS.getMembersCount) def createChatChannel(self, channelName, password = None): try: self.__baseChatCommand(CHAT_COMMANDS.createChatChannel, stringArg1=channelName, stringArg2=password if password is not None else '', ignoreCooldown=False) except ChatError as ex: self._processChatError(CHAT_COMMANDS.createChatChannel, 0, ex) return def destroyChatChannel(self, channelId): self.__baseChannelChatCommand(channelId, CHAT_COMMANDS.destroyChatChannel) def enterChat(self, channelId, password = None): self.__baseChannelChatCommand(channelId, CHAT_COMMANDS.enterChatChannel, stringArg1=password if password is not None else '') return def broadcast(self, channelId, message): if not len(message) or message.isspace(): return message = message.rstrip() if not isCommandMessage(message): try: self.__baseChannelChatCommand(channelId, CHAT_COMMANDS.broadcast, stringArg1=message, ignoreCooldown=False) except ChatError as ex: self._processChatError(CHAT_ACTIONS.broadcast, channelId, ex) else: try: command, int64Arg, int16Arg, stringArg1, stringArg2 = parseCommandMessage(message) self.__baseChannelChatCommand(channelId, command, int64Arg, int16Arg, stringArg1, stringArg2, ignoreCooldown=False) except ChatCommandError as ex: self._processChatError(CHAT_ACTIONS.userChatCommand, channelId, ex) def leaveChat(self, channelId): self.__baseChannelChatCommand(channelId, CHAT_COMMANDS.leaveChatChannel) def onChatActionFailure(self, actionData): MessengerEntry.g_instance.protos.BW.onChatActionFailure(actionData) def onChatAction(self, chatActionData): global g_replayCtrl if g_replayCtrl is None: import BattleReplay g_replayCtrl = BattleReplay.g_replayCtrl if g_replayCtrl.isRecording: g_replayCtrl.cancelSaveCurrMessage() elif g_replayCtrl.isPlaying: g_replayCtrl.onChatAction(chatActionData) return for processor in self.__dataProcessors: getattr(self, processor)(chatActionData) if CHAT_RESPONSES[chatActionData['actionResponse']] != CHAT_RESPONSES.success: self.onChatActionFailure(chatActionData) else: hanlerName = self.__actionHandlers.get(chatActionData['action'], None) if hanlerName: getattr(self, hanlerName)(chatActionData) chId = chatActionData['channel'] commonCallbacks = self.__getChatActionCallbacks(CHAT_ACTIONS[chatActionData['action']], 0) commonCallbacks(chatActionData) if chId != 0: channelCallbacks = self.__getChatActionCallbacks(CHAT_ACTIONS[chatActionData['action']], chId) channelCallbacks(chatActionData) return def requestLastSysMessages(self): self.__baseChatCommand(CHAT_COMMANDS.requestLastSysMessages) def findUsers(self, userNamePattern, onlineMode = None, requestID = None): if onlineMode is None: searchMode = USER_SEARCH_MODE.ALL elif onlineMode: searchMode = USER_SEARCH_MODE.ONLINE else: searchMode = USER_SEARCH_MODE.OFFLINE self.__baseChatCommand(CHAT_COMMANDS.findUser, int16Arg=searchMode, stringArg1=userNamePattern, requestID=requestID) return def requestUsersRoster(self, flags = 0): self.__baseChatCommand(CHAT_COMMANDS.requestUsersRoster, int16Arg=flags) def logVivoxLogin(self): self.__baseChatCommand(CHAT_COMMANDS.logVivoxLogin) def requestFriendStatus(self, friendID = -1): self.__baseChatCommand(CHAT_COMMANDS.requestFriendStatus, int64Arg=friendID) def addFriend(self, friendID, friendName): self.__baseChatCommand(CHAT_COMMANDS.addFriend, int64Arg=friendID, stringArg1=friendName) def createPrivate(self, friendID, friendName): self.__baseChatCommand(CHAT_COMMANDS.createPrivate, int64Arg=friendID, stringArg1=friendName) def removeFriend(self, friendID): self.__baseChatCommand(CHAT_COMMANDS.removeFriend, int64Arg=friendID) def addIgnored(self, ignoredID, ignoredName): self.__baseChatCommand(CHAT_COMMANDS.addIgnored, int64Arg=ignoredID, stringArg1=ignoredName) def removeIgnored(self, ignoredID): self.__baseChatCommand(CHAT_COMMANDS.removeIgnored, int64Arg=ignoredID) def setMuted(self, mutedID, mutedName): self.__baseChatCommand(CHAT_COMMANDS.setMuted, int64Arg=mutedID, stringArg1=mutedName) def unsetMuted(self, mutedID): self.__baseChatCommand(CHAT_COMMANDS.unsetMuted, int64Arg=mutedID) def createPrebattleInvite(self, receiverName, auxText, prebattleID, prebattleType, requestID = None): self.__baseInviteCommand(CHAT_COMMANDS.createInvite, INVITE_TYPES.PREBATTLE, receiverName, prebattleID, prebattleType, stringArg2=auxText, requestID=requestID) def createBarterInvite(self, receiverName, auxText, itemID, requestID = None): self.__baseInviteCommand(CHAT_COMMANDS.createInvite, INVITE_TYPES.BARTER, receiverName, itemID, stringArg2=auxText, requestID=requestID) def acceptPrebattleInvite(self, inviteID, requestID = None): if requestID is None: requestID = self.acquireRequestID() self.base.ackCommand(requestID, CHAT_COMMANDS.acceptInvite.index(), time.time(), inviteID, -1) return def rejectInvite(self, inviteID, requestID = None): if requestID is None: requestID = self.acquireRequestID() self.base.ackCommand(requestID, CHAT_COMMANDS.rejectInvite.index(), time.time(), inviteID, -1) return def getActiveInvites(self): self.__baseInviteCommand(CHAT_COMMANDS.getActiveInvites) def getArchiveInvites(self): self.__baseInviteCommand(CHAT_COMMANDS.getArchiveInvites) def requestVOIPCredentials(self, changePwd = 0): self.__baseChatCommand(CHAT_COMMANDS.requestVOIPCredentials, int16Arg=changePwd) def subscribeChatAction(self, callback, action, channelId = None): cbs = self.__getChatActionCallbacks(action, channelId) cbs += callback def unsubscribeChatAction(self, callback, action, channelId = None): cbs = self.__getChatActionCallbacks(action, channelId) cbs -= callback def setChatActionsCallbacks(self, callbacks): self.__chatActionCallbacks = callbacks def sendChannelChatCommand(self, channelID, command, int64Arg = 0, int16Arg = 0, stringArg1 = '', stringArg2 = ''): self.__baseChannelChatCommand(channelID, command, int64Arg, int16Arg, stringArg1, stringArg2) def _processChatError(self, action, channelId, chatError, requestID = -1): if isinstance(chatError, ChatError): actionData = chatError.messageArgs if chatError.messageArgs is not None else chatError.message else: actionData = '' chatAction = buildChatActionData(action=action, requestID=requestID, channelId=channelId, originatorNickName=self.name, data=actionData, actionResponse=chatError.response if isinstance(chatError, ChatError) else CHAT_RESPONSES.internalError) self.onChatAction(chatAction) return def __getChatActionCallbacks(self, action, channelId): channelId = channelId if channelId is not None else 0 key = (action, channelId) if key not in self.__chatActionCallbacks: handlers = self.__chatActionCallbacks[key] = Event.Event() else: handlers = self.__chatActionCallbacks[key] return handlers def __receiveStreamedData(self, streamID, data): failed = False try: data = zlib.decompress(data) chatMessages = cPickle.loads(data) except: LOG_CURRENT_EXCEPTION() failed = True if not failed: chIds = sorted(chatMessages.keys(), cmp=lambda x, y: cmp(abs(x), abs(y))) for chId in chIds: channelQueue = chatMessages.get(chId, deque()) while True: try: actionData = channelQueue.popleft() self.onChatAction(actionData) except IndexError: break self.__baseChatCommand(CHAT_COMMANDS.initAck, int64Arg=streamID, int16Arg=failed) def __baseChannelChatCommand(self, channelID, command, int64Arg = 0, int16Arg = 0, stringArg1 = '', stringArg2 = '', ignoreCooldown = True): if 0 == channelID: LOG_ERROR('Can`t execute chat channel command for channelId: %s' % (channelID,)) else: if chat_shared.isOperationInCooldown(chat_shared.g_chatCooldownData, command): if ignoreCooldown: return raise ChatCommandInCooldown(command) self.__baseChatCommand(command, channelID, int64Arg, int16Arg, stringArg1, stringArg2) def __baseChatCommand(self, command, channelID = 0, int64Arg = 0, int16Arg = 0, stringArg1 = '', stringArg2 = '', ignoreCooldown = True, requestID = None): if requestID is None: requestID = self.acquireRequestID() if chat_shared.isOperationInCooldown(chat_shared.g_chatCooldownData, command): if not ignoreCooldown: raise ChatCommandInCooldown(command) self.base.chatCommandFromClient(requestID, command.index(), channelID, int64Arg, int16Arg, stringArg1, stringArg2) return def __baseInviteCommand(self, command, inviteType = None, receiverName = '', int64Arg = 0, int16Arg = 0, stringArg1 = '', stringArg2 = '', requestID = None): if requestID is None: requestID = self.acquireRequestID() self.base.inviteCommand(requestID, command.index(), inviteType.index() if inviteType is not None else -1, receiverName, int64Arg, int16Arg, stringArg1, stringArg2) return def __onReceiveInvite(self, chatActionData): inviteID = chatActionData['data'].get('id', None) receivedAt = chatActionData['data'].get('received_at', None) if inviteID is not None and receivedAt is None: requestID = self.acquireRequestID() self.base.ackCommand(requestID, CHAT_COMMANDS.inviteReceived.index(), time.time(), inviteID, -1) return def __dataTimeProcessor(self, actionData): actionData['time'] = tm.makeLocalServerTime(actionData['time']) actionData['sentTime'] = tm.makeLocalServerTime(actionData['sentTime']) def __inviteDataTimeProcessor(self, actionData): isInviteAction = CHAT_ACTIONS[actionData['action']] in (CHAT_ACTIONS.createInvite, CHAT_ACTIONS.receiveInvite, CHAT_ACTIONS.receiveArchiveInvite) if isInviteAction: if actionData.has_key('data'): inviteData = actionData['data'] if 'sent_at' in inviteData: inviteData['sent_at'] = tm.utcToLocalDatetime(tm.makeLocalServerDatetime(inviteData['sent_at'])) if 'received_at' in inviteData: inviteData['received_at'] = tm.utcToLocalDatetime(tm.makeLocalServerDatetime(inviteData['received_at'])) if 'processed_at' in inviteData: inviteData['processed_at'] = tm.utcToLocalDatetime(tm.makeLocalServerDatetime(inviteData['processed_at'])) def __systemMessageTimeProcessor(self, actionData): isSystemMessage = CHAT_ACTIONS[actionData['action']] in (CHAT_ACTIONS.personalSysMessage, CHAT_ACTIONS.sysMessage) if isSystemMessage: if actionData.has_key('data'): messageData = actionData['data'] messageType = messageData['type'] if 'created_at' in messageData: messageData['created_at'] = tm.makeLocalServerDatetime(messageData['created_at']) if 'finished_at' in messageData: messageData['finished_at'] = tm.makeLocalServerDatetime(messageData['finished_at']) if 'started_at' in messageData: messageData['started_at'] = tm.makeLocalServerDatetime(messageData['started_at']) if messageType == SYS_MESSAGE_TYPE.serverReboot.index(): messageData['data'] = tm.makeLocalServerDatetime(messageData['data']) elif messageType == SYS_MESSAGE_TYPE.battleResults.index(): messageData['data']['arenaCreateTime'] = tm.makeLocalServerTime(messageData['data']['arenaCreateTime']) elif messageType == SYS_MESSAGE_TYPE.goldReceived.index(): messageData['data']['date'] = tm.makeLocalServerTime(messageData['data']['date']) elif messageType in (SYS_MESSAGE_TYPE.accountTypeChanged.index(), SYS_MESSAGE_TYPE.premiumBought.index(), SYS_MESSAGE_TYPE.premiumExtended.index(), SYS_MESSAGE_TYPE.premiumExpired.index()): if 'expiryTime' in messageData['data']: messageData['data']['expiryTime'] = tm.makeLocalServerTime(messageData['data']['expiryTime'])
class BrowserController(IBrowserController): _BROWSER_TEXTURE = 'BrowserBg' _ALT_BROWSER_TEXTURE = 'AltBrowserBg' def __init__(self): super(BrowserController, self).__init__() self.__browsers = {} self.__browsersCallbacks = {} self.__browserCreationCallbacks = {} self.__browserIDGenerator = SequenceIDGenerator() self.__eventMgr = Event.EventManager() self.onBrowserAdded = Event.Event(self.__eventMgr) self.onBrowserDeleted = Event.Event(self.__eventMgr) self.__urlMacros = URLMarcos() self.__pendingBrowsers = {} self.__creatingBrowserID = None self.__filters = _getGlobalFilters() return def fini(self): self.__filters = None self.__eventMgr.clear() self.__eventMgr = None self.__urlMacros.clear() self.__urlMacros = None self.__browsersCallbacks.clear() self.__browsersCallbacks = None self.__browsers.clear() self.__browsers = None self.__pendingBrowsers.clear() self.__pendingBrowsers = None self.__browserIDGenerator = None super(BrowserController, self).fini() return def onAvatarBecomePlayer(self): self.__stop() def onDisconnected(self): self.__stop() def addFilterHandler(self, handler): """ Adds given @handler to the browser urls filter chain. Calls it if there is a @tag in url onto opened browser page. Handler should receive url and list of client-specific tags, return bool as flag that routine have to stop """ self.__filters.add(handler) def removeFilterHandler(self, handler): """ Remove given @handler from filtering chain. Handler description can be seen in addFilterhandler method doc-string """ self.__filters.discard(handler) @async @process def load(self, url=None, title=None, showActionBtn=True, showWaiting=True, browserID=None, isAsync=False, browserSize=None, isDefault=True, callback=None, showCloseBtn=False, useBrowserWindow=True, isModal=False, showCreateWaiting=False, handlers=None, showBrowserCallback=None, isSolidBorder=False): if constants.IS_BOOTCAMP_ENABLED: from bootcamp.Bootcamp import g_bootcamp if g_bootcamp.isRunning(): return if showCreateWaiting: Waiting.show('browser/init') url = yield self.__urlMacros.parse(url or GUI_SETTINGS.browser.url) suffix = yield self.__urlMacros.parse(GUI_SETTINGS.browser.params) concatenator = '&' if '?' in url else '?' if suffix not in url: url = concatenator.join([url, suffix]) size = browserSize or BROWSER.SIZE webBrowserID = browserID if browserID is None: browserID = self.__browserIDGenerator.next() webBrowserID = browserID elif type(browserID) is not int: webBrowserID = self.__browserIDGenerator.next() ctx = { 'url': url, 'title': title, 'showActionBtn': showActionBtn, 'showWaiting': showWaiting, 'browserID': browserID, 'size': size, 'isAsync': isAsync, 'showCloseBtn': showCloseBtn, 'showWindow': useBrowserWindow, 'alias': VIEW_ALIAS.BROWSER_WINDOW_MODAL if isModal else VIEW_ALIAS.BROWSER_WINDOW, 'showCreateWaiting': showCreateWaiting, 'handlers': handlers, 'showBrowserCallback': showBrowserCallback, 'isSolidBorder': isSolidBorder } texture = browserID not in self.__browsers and browserID not in self.__pendingBrowsers and self._BROWSER_TEXTURE app = g_appLoader.getApp() if not app: raise AssertionError('Application can not be None') browser = WebBrowser(webBrowserID, app, texture, size, url, handlers=self.__filters) self.__browsers[browserID] = browser if self.__isCreatingBrowser(): LOG_BROWSER('CTRL: Queueing a browser creation: ', browserID, url) self.__pendingBrowsers[browserID] = ctx else: self.__createBrowser(ctx) elif browserID in self.__pendingBrowsers: LOG_BROWSER('CTRL: Re-queuing a browser creation, overriding: ', browserID, url) self.__pendingBrowsers[browserID] = ctx elif browserID in self.__browsers: LOG_BROWSER('CTRL: Re-navigating an existing browser: ', browserID, url) browser = self.__browsers[browserID] browser.navigate(url) browser.changeTitle(title) callback(browserID) return def getBrowser(self, browserID): return self.__browsers.get(browserID) def delBrowser(self, browserID): if browserID in self.__browsers: LOG_BROWSER('CTRL: Deleting a browser: ', browserID) browser = self.__browsers.pop(browserID) self.__clearCallbacks(browserID, browser, True) browser.destroy() if self.__creatingBrowserID == browserID: self.__creatingBrowserID = None self.__tryCreateNextPendingBrowser() if browserID in self.__pendingBrowsers: del self.__pendingBrowsers[browserID] self.onBrowserDeleted(browserID) return def __isCreatingBrowser(self): return self.__creatingBrowserID is not None def __createDone(self, ctx): LOG_BROWSER('CTRL: Finished creating a browser: ', self.__creatingBrowserID) if ctx['showCreateWaiting']: Waiting.hide('browser/init') def __tryCreateNextPendingBrowser(self): self.__creatingBrowserID = None if len(self.__pendingBrowsers) > 0: nextCtx = self.__pendingBrowsers.popitem()[1] self.__createBrowser(nextCtx) return def __createBrowser(self, ctx): browserID = ctx['browserID'] LOG_BROWSER('CTRL: Creating a browser: ', browserID, ctx['url']) self.__creatingBrowserID = browserID if not self.__browsers[browserID].create(): LOG_BROWSER('CTRL: Failed the create step: ', browserID) self.delBrowser(browserID) self.__tryCreateNextPendingBrowser() return else: self.onBrowserAdded(browserID) def createBrowserTimeout(): LOG_BROWSER('CTRL: Browser create timed out') createNextBrowser() timeoutid = BigWorld.callback(30.0, createBrowserTimeout) def createNextBrowser(): LOG_BROWSER('CTRL: Triggering create of next browser from: ', browserID) BigWorld.cancelCallback(timeoutid) creation = self.__browserCreationCallbacks.pop(browserID, None) if creation is not None: self.__browsers[ browserID].onCanCreateNewBrowser -= creation BigWorld.callback(1.0, self.__tryCreateNextPendingBrowser) return def failedCreationCallback(url): LOG_BROWSER('CTRL: Failed a creation: ', browserID, url) self.__clearCallbacks(browserID, self.__browsers[browserID], False) self.delBrowser(browserID) def successfulCreationCallback(url, isLoaded, httpStatusCode=None): LOG_BROWSER('CTRL: Ready to show: ', browserID, isLoaded, url) self.__clearCallbacks(browserID, self.__browsers[browserID], False) if isLoaded: self.__showBrowser(browserID, ctx) else: LOG_WARNING('Browser request url was not loaded!', url) g_eventBus.handleEvent( BrowserEvent(BrowserEvent.BROWSER_CREATED, ctx=ctx)) self.__createDone(ctx) self.__browsers[ browserID].onCanCreateNewBrowser += createNextBrowser self.__browserCreationCallbacks[browserID] = createNextBrowser self.__browsers[ browserID].onFailedCreation += failedCreationCallback if ctx['isAsync']: self.__browsersCallbacks[browserID] = ( None, successfulCreationCallback, failedCreationCallback) self.__browsers[ browserID].onLoadEnd += successfulCreationCallback else: self.__browsersCallbacks[browserID] = ( successfulCreationCallback, None, failedCreationCallback) self.__browsers[ browserID].onReady += successfulCreationCallback return def __stop(self): while self.__browsers: browserID, browser = self.__browsers.popitem() self.__clearCallbacks(browserID, browser, True) browser.destroy() def __clearCallbacks(self, browserID, browser, incDelayedCreation): ready, loadEnd, failed = self.__browsersCallbacks.pop( browserID, (None, None, None)) if browser is not None: if failed is not None: browser.onFailedCreation -= failed if ready is not None: browser.onReady -= ready if loadEnd is not None: browser.onLoadEnd -= loadEnd if incDelayedCreation: creation = self.__browserCreationCallbacks.pop(browserID, None) if browser is not None and creation is not None: browser.onCanCreateNewBrowser -= creation return def __showBrowser(self, browserID, ctx): LOG_BROWSER('CTRL: Showing a browser: ', browserID, ctx['url']) if ctx.get('showWindow'): alias = ctx['alias'] g_eventBus.handleEvent( LoadViewEvent(alias, getViewName(alias, browserID), ctx=ctx), EVENT_BUS_SCOPE.LOBBY) showBrowserCallback = ctx.get('showBrowserCallback') if showBrowserCallback: showBrowserCallback()
class InvitesManager(UsersInfoHelper): __clanInfo = None def __init__(self, loader): super(InvitesManager, self).__init__() self.__loader = loader self._IDGen = SequenceIDGenerator() self._IDMap = {} self.__invites = {} self.__unreadInvitesCount = 0 self.__eventManager = Event.EventManager() self.__acceptChain = None self.onInvitesListInited = Event.Event(self.__eventManager) self.onReceivedInviteListModified = Event.Event(self.__eventManager) self.onSentInviteListModified = Event.Event(self.__eventManager) self.__isInBattle = False return def __del__(self): LOG_DEBUG('InvitesManager deleted') super(InvitesManager, self).__del__() def init(self): self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED g_messengerEvents.users.onUsersListReceived += self.__me_onUsersListReceived g_playerEvents.onPrebattleInvitesChanged += self.__pe_onPrebattleInvitesChanged g_playerEvents.onPrebattleInvitationsChanged += self.__pe_onPrebattleInvitationsChanged g_playerEvents.onPrebattleInvitesStatus += self.__pe_onPrebattleInvitesStatus def fini(self): self.__clearAcceptChain() self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED self.__loader = None g_messengerEvents.users.onUsersListReceived -= self.__me_onUsersListReceived g_playerEvents.onPrebattleInvitationsChanged -= self.__pe_onPrebattleInvitationsChanged g_playerEvents.onPrebattleInvitesChanged -= self.__pe_onPrebattleInvitesChanged g_playerEvents.onPrebattleInvitesStatus -= self.__pe_onPrebattleInvitesStatus self.clear() return def start(self): self.__isInBattle = False if self.__inited & PRB_INVITES_INIT_STEP.STARTED == 0: self.__inited |= PRB_INVITES_INIT_STEP.STARTED if self.__inited == PRB_INVITES_INIT_STEP.INITED: self.onInvitesListInited() def clear(self): self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED self.__clearInvites() self._IDMap = {} self.__eventManager.clear() def onAvatarBecomePlayer(self): self.__isInBattle = True self.__clearAcceptChain() @storage_getter('users') def users(self): return None def isInited(self): return self.__inited == PRB_INVITES_INIT_STEP.INITED def acceptInvite(self, inviteID, postActions = None): try: invite = self.__invites[inviteID] except KeyError: LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap) return self.__clearAcceptChain() if not postActions: invite.accept() else: self.__acceptChain = _AcceptInvitesPostActions(invite, postActions) self.__acceptChain.onStopped += self.__accept_onPostActionsStopped self.__acceptChain.start() if self.__unreadInvitesCount > 0: self.__unreadInvitesCount -= 1 def declineInvite(self, inviteID): try: invite = self.__invites[inviteID] except KeyError: LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap) return invite.decline() if self.__unreadInvitesCount > 0: self.__unreadInvitesCount -= 1 def revokeInvite(self, inviteID): try: invite = self.__invites[inviteID] except KeyError: LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap) return invite.revoke() if self.__unreadInvitesCount > 0: self.__unreadInvitesCount -= 1 def canAcceptInvite(self, invite): result = False if invite.alwaysAvailable is True: result = True elif invite.clientID in self.__invites: dispatcher = self.__loader.getDispatcher() if dispatcher: prbFunctional = dispatcher.getPrbFunctional() unitFunctional = dispatcher.getUnitFunctional() preQueueFunctional = dispatcher.getPreQueueFunctional() if invite.alreadyJoined: return False if prbFunctional and prbFunctional.hasLockedState() or unitFunctional and unitFunctional.hasLockedState() or preQueueFunctional and preQueueFunctional.hasLockedState(): return False another = invite.anotherPeriphery if another: if g_preDefinedHosts.periphery(invite.peripheryID) is None: LOG_ERROR('Periphery not found') result = False elif g_lobbyContext.getCredentials() is None: LOG_ERROR('Login info not found') result = False elif g_preDefinedHosts.isRoamingPeriphery(invite.peripheryID) and not isRoamingEnabled(g_itemsCache.items.stats.attributes): LOG_ERROR('Roaming is not supported') result = False else: result = invite.clientID > 0 and invite.isActive() else: result = invite.clientID > 0 and invite.isActive() return result def canDeclineInvite(self, invite): result = False if invite.clientID in self.__invites: result = invite.clientID > 0 and invite.isActive() return result def canRevokeInvite(self, invite): result = False if invite.clientID in self.__invites: result = invite.clientID > 0 and invite.isActive() and invite.creatorDBID == getPlayerDatabaseID() return result def getInvites(self, incoming = None, version = None, onlyActive = None): result = self.__invites.values() if incoming is not None: result = filter(lambda item: item.isIncoming() is incoming, result) if version is not None: result = filter(lambda item: item.getVersion() == version, result) if onlyActive is not None: result = filter(lambda item: item.isActive() is onlyActive, result) return result def getInvite(self, inviteID): invite = None if inviteID in self.__invites: invite = self.__invites[inviteID] return invite def getReceivedInviteCount(self): return len(self.getReceivedInvites()) def getReceivedInvites(self, IDs = None): result = self.getInvites(incoming=True) if IDs is not None: result = filter(lambda item: item.clientID in IDs, result) return result def getSentInvites(self, IDs = None): result = self.getInvites(incoming=False) if IDs is not None: result = filter(lambda item: item.clientID in IDs, result) return result def getSentInviteCount(self): return len(self.getSentInvites()) def getUnreadCount(self): return self.__unreadInvitesCount def resetUnreadCount(self): self.__unreadInvitesCount = 0 def onUserNamesReceived(self, names): updated = defaultdict(list) rosterGetter = self.users.getUser inviteMaker = self._getNewInviteMaker(rosterGetter) prebattleInvitations = _getNewInvites() for invite in self.getInvites(version=_INVITE_VERSION.NEW): if invite.creatorDBID in names or invite.receiverDBID in names: inviteData = prebattleInvitations.get(invite.id) inviteID, invite = inviteMaker(inviteData) if inviteData and self._updateInvite(invite, rosterGetter): updated[invite.isIncoming()].append(inviteID) for isIncoming, event in ((True, self.onReceivedInviteListModified), (False, self.onSentInviteListModified)): if updated[isIncoming]: event([], updated[isIncoming], []) def _makeInviteID(self, prebattleID, peripheryID, senderDBID, receiverDBID): inviteKey = (prebattleID, peripheryID, senderDBID, receiverDBID) inviteID = self._IDMap.get(inviteKey) if inviteID is None: inviteID = self._IDGen.next() self._IDMap[inviteKey] = inviteID return inviteID def _addInvite(self, invite, userGetter): if self.__isInviteSenderIgnoredInBattle(invite, userGetter): return False self.__invites[invite.clientID] = invite if invite.isActive(): self.__unreadInvitesCount += 1 return True def _updateInvite(self, other, userGetter): inviteID = other.clientID invite = self.__invites[inviteID] if invite == other or self.__isInviteSenderIgnoredInBattle(invite, userGetter): return False prevCount = invite.count invite = invite._merge(other) self.__invites[inviteID] = invite if invite.isActive() and prevCount < invite.count: self.__unreadInvitesCount += 1 return True def _delInvite(self, inviteID): result = inviteID in self.__invites if result: self.__invites.pop(inviteID) return result def _buildReceivedInvitesList(self, invitesLists): if self.__inited & PRB_INVITES_INIT_STEP.DATA_BUILD == 0: self.__inited |= PRB_INVITES_INIT_STEP.DATA_BUILD self.__clearInvites() userGetter = self.users.getUser for invitesData, maker in invitesLists: for item in invitesData: _, invite = maker(item) if invite: self._addInvite(invite, userGetter) if g_appLoader.getSpaceID() != GUI_GLOBAL_SPACE_ID.BATTLE: self.syncUsersInfo() def _rebuildInvitesLists(self): rosterGetter = self.users.getUser self._buildReceivedInvitesList([(_getOldInvites().items(), self._getOldInviteMaker(rosterGetter)), (_getNewInvites().values(), self._getNewInviteMaker(rosterGetter))]) def _getOldInviteMaker(self, rosterGetter): receiver = getPlayerName() receiverDBID = getPlayerDatabaseID() receiverClanAbbrev = g_lobbyContext.getClanAbbrev(self.__clanInfo) def _inviteMaker(item): (prebattleID, peripheryID), data = item inviteID = self._makeInviteID(prebattleID, peripheryID, data['creatorDBID'], receiverDBID) if data is not None: invite = PrbInviteWrapper(clientID=inviteID, receiver=receiver, receiverDBID=receiverDBID, receiverClanAbbrev=receiverClanAbbrev, peripheryID=peripheryID, prebattleID=prebattleID, **data) else: invite = None return (inviteID, invite) return _inviteMaker def _getNewInviteMaker(self, rosterGetter): def _getUserName(userDBID): name, abbrev = ('', None) if userDBID: if g_appLoader.getSpaceID() == GUI_GLOBAL_SPACE_ID.BATTLE: name, abbrev = g_battleCtrl.getCtx().getPlayerFullNameParts(accID=userDBID, showVehShortName=False)[1:3] if not name: userName = self.getUserName(userDBID) userClanAbbrev = self.getUserClanAbbrev(userDBID) user = rosterGetter(userDBID) if user and user.hasValidName(): name, abbrev = userName, userClanAbbrev return (name, abbrev) def _inviteMaker(item): peripheryID, prebattleID = PrbInvitationWrapper.getPrbInfo(item.get('info', {})) senderDBID = item.get('senderDBID', 0) receiverDBID = item.get('receiverDBID', 0) inviteID = self._makeInviteID(prebattleID, peripheryID, senderDBID, receiverDBID) senderName, senderClanAbbrev = _getUserName(senderDBID) receiverName, receiverClanAbbrev = _getUserName(receiverDBID) return (inviteID, PrbInvitationWrapper(inviteID, sender=senderName, senderClanAbbrev=senderClanAbbrev, receiver=receiverName, receiverClanAbbrev=receiverClanAbbrev, **item)) return _inviteMaker def __initReceivedInvites(self): step = PRB_INVITES_INIT_STEP.CONTACTS_RECEIVED if self.__inited & step != step: return self._rebuildInvitesLists() if self.__inited == PRB_INVITES_INIT_STEP.INITED: self.onInvitesListInited() def __clearAcceptChain(self): if self.__acceptChain is not None: self.__acceptChain.onStopped -= self.__accept_onPostActionsStopped self.__acceptChain.stop() self.__acceptChain = None return def __me_onUsersListReceived(self, tags): doInit = False if USER_TAG.FRIEND in tags: doInit = True step = PRB_INVITES_INIT_STEP.FRIEND_RECEIVED if self.__inited & step == 0: self.__inited |= step if USER_TAG.IGNORED in tags: doInit = True step = PRB_INVITES_INIT_STEP.IGNORED_RECEIVED if self.__inited & step == 0: self.__inited |= step if doInit: self.__initReceivedInvites() def __pe_onPrebattleInvitesChanged(self, diff): step = PRB_INVITES_INIT_STEP.CONTACTS_RECEIVED if self.__inited & step != step: LOG_DEBUG('Received invites are ignored. Manager waits for client will receive contacts') return if ('prebattleInvites', '_r') in diff: self._rebuildInvitesLists() if 'prebattleInvites' in diff: self.__updateOldPrebattleInvites(_getOldInvites()) def __pe_onPrebattleInvitationsChanged(self, invitations): step = PRB_INVITES_INIT_STEP.CONTACTS_RECEIVED if self.__inited & step != step: LOG_DEBUG('Received invites are ignored. Manager waits for client will receive contacts') return self.__updateNewPrebattleInvites(invitations) def __pe_onPrebattleInvitesStatus(self, dbID, name, status): if status != PREBATTLE_INVITE_STATUS.OK: statusName = PREBATTLE_INVITE_STATUS_NAMES[status] SystemMessages.pushI18nMessage('#system_messages:invite/status/%s' % statusName, name=name, type=SystemMessages.SM_TYPE.Warning) def __updateOldPrebattleInvites(self, prbInvites): added = [] changed = [] deleted = [] modified = False rosterGetter = self.users.getUser inviteMaker = self._getOldInviteMaker(rosterGetter) for item in prbInvites.iteritems(): inviteID, invite = inviteMaker(item) if invite is None: if self._delInvite(inviteID): modified = True deleted.append(inviteID) continue inList = inviteID in self.__invites if not inList: if self._addInvite(invite, rosterGetter): modified = True added.append(inviteID) elif self._updateInvite(invite, rosterGetter): modified = True changed.append(inviteID) if modified: self.onReceivedInviteListModified(added, changed, deleted) return def __updateNewPrebattleInvites(self, prbInvites): added = defaultdict(list) changed = defaultdict(list) deleted = defaultdict(list) modified = dict(((v, False) for v in (True, False))) rosterGetter = self.users.getUser inviteMaker = self._getNewInviteMaker(rosterGetter) newInvites = {} for data in prbInvites.itervalues(): inviteID, invite = inviteMaker(data) if inviteID not in newInvites or invite.createTime > newInvites[inviteID].createTime: newInvites[inviteID] = invite for invite in self.getInvites(version=_INVITE_VERSION.NEW): inviteID = invite.clientID if inviteID not in newInvites and self._delInvite(inviteID): isIncoming = invite.isIncoming() modified[isIncoming] = True deleted[isIncoming].append(inviteID) else: continue for inviteID, invite in newInvites.iteritems(): isIncoming = invite.isIncoming() if inviteID not in self.__invites: if self._addInvite(invite, rosterGetter): modified[isIncoming] = True added[isIncoming].append(inviteID) elif self._updateInvite(invite, rosterGetter): modified[isIncoming] = True changed[isIncoming].append(inviteID) for isIncoming, event in ((True, self.onReceivedInviteListModified), (False, self.onSentInviteListModified)): if modified[isIncoming]: event(added[isIncoming], changed[isIncoming], deleted[isIncoming]) self.syncUsersInfo() def __accept_onPostActionsStopped(self, isCompleted): if not isCompleted: return invite = self.__acceptChain.invite invite.accept() if self.__unreadInvitesCount > 0: self.__unreadInvitesCount -= 1 def __clearInvites(self): self.__invites.clear() self.__unreadInvitesCount = 0 def __isInviteSenderIgnoredInBattle(self, invite, userGetter): return isInviteSenderIgnoredInBattle(userGetter(invite.creatorDBID), g_settings.userPrefs.invitesFromFriendsOnly, invite.isCreatedInBattle())
class BrowserController(Controller): _BROWSER_TEXTURE = 'BrowserBg' _ALT_BROWSER_TEXTURE = 'AltBrowserBg' def __init__(self, proxy): super(BrowserController, self).__init__(proxy) self.__browsers = {} self.__browsersCallbacks = {} self.__browserIDGenerator = SequenceIDGenerator() self.__eventMgr = Event.EventManager() self.onBrowserAdded = Event.Event(self.__eventMgr) self.onBrowserDeleted = Event.Event(self.__eventMgr) self.__urlMacros = URLMarcos() def fini(self): self.__eventMgr.clear() self.__eventMgr = None self.__urlMacros.clear() self.__urlMacros = None self.__browserIDGenerator = None super(BrowserController, self).fini() def onAvatarBecomePlayer(self): self.__stop() def onDisconnected(self): self.__stop() @async @process def load(self, url = None, title = None, showActionBtn = True, showWaiting = True, browserID = None, isAsync = False, browserSize = None, background = None, isDefault = True, callback = None, showCloseBtn = False): url = url or GUI_SETTINGS.browser.url suffix = yield self.__urlMacros.parse(GUI_SETTINGS.browser.params) concatenator = '&' if '?' in url else '?' if suffix not in url: url = concatenator.join([url, suffix]) size = browserSize or BROWSER.SIZE background = background or BROWSER.BACKGROUND if browserID is None: browserID = self.__browserIDGenerator.next() if browserID not in self.__browsers: texture = self._BROWSER_TEXTURE if isDefault else self._ALT_BROWSER_TEXTURE app = g_appLoader.getApp() assert app, 'Application can not be None' self.__browsers[browserID] = WebBrowser(browserID, app, texture, size, url, backgroundUrl=background) self.onBrowserAdded(browserID) ctx = {'url': url, 'title': title, 'showActionBtn': showActionBtn, 'showWaiting': showWaiting, 'browserID': browserID, 'size': size, 'isDefault': isDefault, 'isAsync': isAsync, 'showCloseBtn': showCloseBtn} def browserCallback(*args): self.__clearCallback(browserID) self.__showBrowser(browserID, ctx) if isAsync: self.__browsersCallbacks[browserID] = (None, browserCallback) self.__browsers[browserID].onLoadEnd += browserCallback else: self.__browsersCallbacks[browserID] = (browserCallback, None) self.__browsers[browserID].onLoadStart += browserCallback callback(browserID) def getBrowser(self, browserID): return self.__browsers.get(browserID) def delBrowser(self, browserID): if browserID in self.__browsers: browser = self.__browsers.pop(browserID) loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None)) if loadStart is not None: browser.onLoadStart -= loadStart if loadEnd is not None: browser.onLoadEnd -= loadEnd browser.destroy() self.onBrowserDeleted(browserID) def __stop(self): while self.__browsers: browserID, browser = self.__browsers.popitem() loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None)) if loadStart is not None: browser.onLoadStart -= loadStart if loadEnd is not None: browser.onLoadEnd -= loadEnd browser.destroy() def __clearCallback(self, browserID): if browserID in self.__browsersCallbacks: loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None)) if loadStart is not None: self.__browsers[browserID].onLoadStart -= loadStart if loadEnd is not None: self.__browsers[browserID].onLoadEnd -= loadEnd def __showBrowser(self, browserID, ctx): g_eventBus.handleEvent(LoadViewEvent(VIEW_ALIAS.BROWSER_WINDOW, getViewName(VIEW_ALIAS.BROWSER_WINDOW, browserID), ctx=ctx), EVENT_BUS_SCOPE.LOBBY)
class BWChatProvider(object): __slots__ = ('__weakref__', '__handlers', '__msgFilters', '__coolDown', '__idGen', '__isEnabled', '__queue', '__battleCmdCooldowns') def __init__(self): super(BWChatProvider, self).__init__() self.__handlers = defaultdict(set) self.__msgFilters = None self.__coolDown = _ChatCooldownManager() self.__battleCmdCooldowns = [] self.__idGen = SequenceIDGenerator() self.__isEnabled = False self.__queue = [] return def clear(self): self.__handlers.clear() self.__battleCmdCooldowns = [] BattleReplay.g_replayCtrl.delDataCallback( CallbackDataNames.BW_CHAT2_REPLAY_ACTION_RECEIVED_CALLBACK, self.__onActionReceivedFromReplay) def goToReplay(self): BattleReplay.g_replayCtrl.setDataCallback( CallbackDataNames.BW_CHAT2_REPLAY_ACTION_RECEIVED_CALLBACK, self.__onActionReceivedFromReplay) def setEnable(self, value): if self.__isEnabled == value: return self.__isEnabled = value if self.__isEnabled: self.__sendActionsFromQueue() else: self.__queue = [] def doAction(self, actionID, args=None, response=False, skipCoolDown=False): success, reqID = False, 0 if self.__isCooldownInProcess(actionID, args): if not skipCoolDown: g_messengerEvents.onErrorReceived( createCoolDownError(actionID, self.__getCooldownTime(actionID, args))) else: if response: reqID = self.__idGen.next() if self.__isEnabled: success = self.__sendAction(actionID, reqID, args) else: success = self.__addActionToQueue(actionID, reqID, args) return (success, reqID) def onActionReceived(self, actionID, reqID, args): if BattleReplay.g_replayCtrl.isRecording and self.__isActionWrittenToReplay( actionID): BattleReplay.g_replayCtrl.serializeCallbackData( CallbackDataNames.BW_CHAT2_REPLAY_ACTION_RECEIVED_CALLBACK, (actionID, reqID, args)) handlers = self.__handlers[actionID] for handler in handlers: try: handler((actionID, reqID), args) except TypeError: LOG_ERROR('Handler has been invoked with error', handler) LOG_CURRENT_EXCEPTION() def setFilters(self, msgFilterChain): self.__msgFilters = msgFilterChain def filterInMessage(self, message): text = message.text senderDBID = message.accountDBID if senderDBID > 0: text = self.__msgFilters.chainIn(senderDBID, text) else: senderAvatarID = message.avatarSessionID if senderAvatarID: text = self.__msgFilters.chainIn(senderAvatarID, text) if not text: result = None else: message.text = text result = message return result def filterOutMessage(self, text, limits): return self.__msgFilters.chainOut(text, limits) def setActionCoolDown(self, actionID, coolDown, targetID=0): command = _ACTIONS.battleChatCommandFromActionID(actionID) if command and command.name not in CHAT_COMMANDS_THAT_IGNORE_COOLDOWNS: currTime = BigWorld.time() addCoolDowns(currTime, self.__battleCmdCooldowns, command.id, command.name, command.cooldownPeriod, targetID) else: self.__coolDown.process(actionID, coolDown) def isActionInCoolDown(self, actionID): command = _ACTIONS.battleChatCommandFromActionID(actionID) if command: return [ cdData for cdData in self.__battleCmdCooldowns if cdData.cmdID == actionID ] return self.__coolDown.isInProcess(actionID) def getActionCooldownData(self, actionID): command = _ACTIONS.battleChatCommandFromActionID(actionID) if command: return [ cdData for cdData in self.__battleCmdCooldowns if cdData.cmdID == actionID ] return [] def clearActionCoolDown(self, actionID): command = _ACTIONS.battleChatCommandFromActionID(actionID) if command: removeList = [ cdData for cdData in self.__battleCmdCooldowns if cdData.cmdID == command.id ] if removeList: for dataForRemoval in removeList: self.__battleCmdCooldowns.remove(dataForRemoval) else: self.__coolDown.reset(actionID) def registerHandler(self, actionID, handler): handlers = self.__handlers[actionID] if handler in handlers: LOG_WARNING('Handler already is exist', actionID, handler) else: if not hasattr(handler, '__self__') or not isinstance( handler.__self__, ActionsHandler): LOG_ERROR('Class of handler is not subclass of ActionsHandler', handler) return if callable(handler): handlers.add(handler) else: LOG_ERROR('Handler is invalid', handler) def unregisterHandler(self, actionID, handler): handlers = self.__handlers[actionID] if handler in handlers: handlers.remove(handler) def __sendAction(self, actionID, reqID, args=None): player = BigWorld.player() if not player: LOG_ERROR('Player is not defined') return False player.base.messenger_onActionByClient_chat2(actionID, reqID, args or messageArgs()) return True def __addActionToQueue(self, actionID, reqID, args=None): self.__queue.append((actionID, reqID, args)) return True def __sendActionsFromQueue(self): invokedIDs = set() while self.__queue: actionID, reqID, args = self.__queue.pop() if actionID in invokedIDs: LOG_WARNING( 'Action is ignored, your must send action after event "showGUI" is invoked', actionID, reqID, args) continue self.__sendAction(actionID, reqID, args) invokedIDs.add(actionID) @staticmethod def __isActionWrittenToReplay(actionID): return actionID == _ACTIONS.INIT_BATTLE_CHAT or _ACTIONS.battleChatCommandFromActionID( actionID) is not None def __onActionReceivedFromReplay(self, actionID, reqID, args): self.onActionReceived(actionID, reqID, args) def __isCooldownInProcess(self, actionID, args=None): command = _ACTIONS.battleChatCommandFromActionID(actionID) if command: currTime = BigWorld.time() targetID = args['int32Arg1'] sndrBlockReason = areSenderCooldownsActive( currTime, self.__battleCmdCooldowns, actionID, targetID) cdTime = sndrBlockReason.cooldownEnd - currTime if sndrBlockReason is not None else 0 return command.name not in CHAT_COMMANDS_THAT_IGNORE_COOLDOWNS and sndrBlockReason is not None and cdTime > 0 else: return self.__coolDown.isInProcess(actionID) def __getCooldownTime(self, actionID, args=None): command = _ACTIONS.battleChatCommandFromActionID(actionID) if command: currTime = BigWorld.time() targetID = args['int32Arg1'] sndrBlockReason = areSenderCooldownsActive( currTime, self.__battleCmdCooldowns, actionID, targetID) cdTime = round(sndrBlockReason.cooldownEnd - currTime, 1) if sndrBlockReason is not None else 0 return cdTime else: self.__coolDown.getTime(actionID) return
def _generateUserName(): global _g_namesGenerator if _g_namesGenerator is None: _g_namesGenerator = SequenceIDGenerator() return '%s %d' % (USER_DEFAULT_NAME_PREFIX, _g_namesGenerator.next())
class BrowserController(Controller): _BROWSER_TEXTURE = 'BrowserBg' _ALT_BROWSER_TEXTURE = 'AltBrowserBg' def __init__(self, proxy): super(BrowserController, self).__init__(proxy) self.__browsers = {} self.__browsersCallbacks = {} self.__browserIDGenerator = SequenceIDGenerator() self.__eventMgr = Event.EventManager() self.onBrowserAdded = Event.Event(self.__eventMgr) self.onBrowserDeleted = Event.Event(self.__eventMgr) self.__urlMacros = URLMarcos() def fini(self): self.__eventMgr.clear() self.__eventMgr = None self.__urlMacros.clear() self.__urlMacros = None self.__browserIDGenerator = None super(BrowserController, self).fini() return def onAvatarBecomePlayer(self): self.__stop() def onDisconnected(self): self.__stop() @async @process def load(self, url = None, title = None, showActionBtn = True, showWaiting = True, browserID = None, isAsync = False, browserSize = None, isDefault = True, callback = None, showCloseBtn = False): url = yield self.__urlMacros.parse(url or GUI_SETTINGS.browser.url) suffix = yield self.__urlMacros.parse(GUI_SETTINGS.browser.params) concatenator = '&' if '?' in url else '?' if suffix not in url: url = concatenator.join([url, suffix]) size = browserSize or BROWSER.SIZE if browserID is None: browserID = self.__browserIDGenerator.next() if browserID not in self.__browsers: texture = self._BROWSER_TEXTURE if isDefault else self._ALT_BROWSER_TEXTURE app = g_appLoader.getApp() if not app: raise AssertionError('Application can not be None') self.__browsers[browserID] = WebBrowser(browserID, app, texture, size, url) self.onBrowserAdded(browserID) ctx = {'url': url, 'title': title, 'showActionBtn': showActionBtn, 'showWaiting': showWaiting, 'browserID': browserID, 'size': size, 'isDefault': isDefault, 'isAsync': isAsync, 'showCloseBtn': showCloseBtn} def browserCallback(*args): self.__clearCallback(browserID) self.__showBrowser(browserID, ctx) def browserAsyncCallback(url, isLoaded): self.__clearCallback(browserID) if isLoaded: self.__showBrowser(browserID, ctx) else: LOG_WARNING('Browser async request url was not loaded!', url) self.__browsersCallbacks[browserID] = isAsync and (None, browserCallback) self.__browsers[browserID].onLoadEnd += browserAsyncCallback else: self.__browsersCallbacks[browserID] = (browserCallback, None) self.__browsers[browserID].onLoadStart += browserCallback callback(browserID) return def getBrowser(self, browserID): return self.__browsers.get(browserID) def delBrowser(self, browserID): if browserID in self.__browsers: browser = self.__browsers.pop(browserID) loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None)) if loadStart is not None: browser.onLoadStart -= loadStart if loadEnd is not None: browser.onLoadEnd -= loadEnd browser.destroy() self.onBrowserDeleted(browserID) return def __stop(self): while self.__browsers: browserID, browser = self.__browsers.popitem() loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None)) if loadStart is not None: browser.onLoadStart -= loadStart if loadEnd is not None: browser.onLoadEnd -= loadEnd browser.destroy() return def __clearCallback(self, browserID): if browserID in self.__browsersCallbacks: loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None)) if loadStart is not None: self.__browsers[browserID].onLoadStart -= loadStart if loadEnd is not None: self.__browsers[browserID].onLoadEnd -= loadEnd return def __showBrowser(self, browserID, ctx): g_eventBus.handleEvent(LoadViewEvent(VIEW_ALIAS.BROWSER_WINDOW, getViewName(VIEW_ALIAS.BROWSER_WINDOW, browserID), ctx=ctx), EVENT_BUS_SCOPE.LOBBY)
class RibbonsAggregator(object): sessionProvider = dependency.descriptor(IBattleSessionProvider) def __init__(self): super(RibbonsAggregator, self).__init__() self.__feedbackProvider = None self.__vehicleStateCtrl = None self.__cache = _RibbonsCache() self.__accumulatedRibbons = _RibbonsCache() self.__rules = {} self.__idGenerator = SequenceIDGenerator() self.onRibbonAdded = Event.Event() self.onRibbonUpdated = Event.Event() self.__isStarted = False self.__isSuspended = False self.__isInPostmortemMode = False return def start(self): self.__isStarted = True if self.__feedbackProvider is None: self.__feedbackProvider = self.sessionProvider.shared.feedback if self.__feedbackProvider is not None: self.__feedbackProvider.onPlayerFeedbackReceived += self._onPlayerFeedbackReceived if self.__vehicleStateCtrl is None: self.__vehicleStateCtrl = self.sessionProvider.shared.vehicleState if self.__vehicleStateCtrl is not None: self.__vehicleStateCtrl.onPostMortemSwitched += self._onPostMortemSwitched self.__vehicleStateCtrl.onRespawnBaseMoving += self.__onRespawnBaseMoving return def suspend(self): if self.__isStarted: self.__isSuspended = True def resume(self): if self.__isSuspended: self.__isSuspended = False def stop(self): self.__isStarted = False self.__isSuspended = False self.clearRibbonsData() if self.__feedbackProvider is not None: self.__feedbackProvider.onPlayerFeedbackReceived -= self._onPlayerFeedbackReceived self.__feedbackProvider = None if self.__vehicleStateCtrl is not None: self.__vehicleStateCtrl.onPostMortemSwitched -= self._onPostMortemSwitched self.__vehicleStateCtrl.onRespawnBaseMoving -= self.__onRespawnBaseMoving self.__vehicleStateCtrl = None return def getRibbon(self, ribbonID): return self.__cache.get(ribbonID, None) def resetRibbonData(self, ribbonID): ribbon = self.__cache.pop(ribbonID) if ribbon is not None and ribbon.getType( ) in _ACCUMULATED_RIBBON_TYPES: self.__accumulatedRibbons.add(ribbon) return def clearRibbonsData(self): self.__cache.clear() self.__accumulatedRibbons.clear() def _onPostMortemSwitched(self, noRespawnPossible, respawnAvailable): self.__isInPostmortemMode = True def __onRespawnBaseMoving(self): self.__isInPostmortemMode = False def _onPlayerFeedbackReceived(self, events): def _ribbonsGenerator(events): for e in events: r = _createRibbonFromPlayerFeedbackEvent( self.__idGenerator.next(), e) if r is not None: yield r return self._aggregateRibbons(_ribbonsGenerator(events)) def _aggregateRibbons(self, ribbons): aggregatedRibbons = {} for ribbon in ribbons: if self.__isSuspended and ribbon.getType( ) not in _ACCUMULATED_RIBBON_TYPES: continue if ribbon.getType() in aggregatedRibbons: temporaryRibbons = aggregatedRibbons[ribbon.getType()] for temporaryRibbon in temporaryRibbons: if temporaryRibbon.aggregate(ribbon): break else: temporaryRibbons.append(ribbon) aggregatedRibbons[ribbon.getType()] = [ribbon] filteredRibbons = self.__filterRibbons(aggregatedRibbons) sortedRibbons = self.__getSortedList(filteredRibbons) for ribbon in sortedRibbons: etype = ribbon.getType() if etype in _NOT_CACHED_RIBBON_TYPES: self.__cache.add(ribbon) self.onRibbonAdded(ribbon) for cachedRibbon in self.__cache.iterByType(etype): if cachedRibbon.aggregate(ribbon): if not self.__isSuspended: updateData = cachedRibbon if cachedRibbon.isAggregating else ribbon self.onRibbonUpdated(updateData) break else: if etype in _ACCUMULATED_RIBBON_TYPES: for accumulatedRibbon in self.__accumulatedRibbons.iterByType( etype): if accumulatedRibbon.aggregate(ribbon): if not self.__isSuspended: self.__accumulatedRibbons.pop( accumulatedRibbon.getID()) self.__cache.add(accumulatedRibbon) self.onRibbonAdded(accumulatedRibbon) break else: if self.__isSuspended: self.__accumulatedRibbons.add(ribbon) else: self.__cache.add(ribbon) self.onRibbonAdded(ribbon) if not self.__isSuspended: self.__cache.add(ribbon) self.onRibbonAdded(ribbon) def __filterRibbons(self, ribbons): if self.__isInPostmortemMode and not avatar_getter.isObserver(): for rType in _RIBBON_TYPES_EXCLUDED_IN_POSTMORTEM: if rType in ribbons: del ribbons[rType] if BATTLE_EFFICIENCY_TYPES.DESTRUCTION in ribbons: killRibbons = dict( ((r.getVehicleID(), r) for r in ribbons[BATTLE_EFFICIENCY_TYPES.DESTRUCTION])) damageRibbons = dict( ((t, ribbons[t]) for t in _RIBBON_TYPES_AGGREGATED_WITH_KILL_RIBBON if t in ribbons)) for rType, tmpRibbons in damageRibbons.iteritems(): filteredRibbons = [] for tmpRibbon in tmpRibbons: if tmpRibbon.getVehicleID() in killRibbons: killRibbon = killRibbons[tmpRibbon.getVehicleID()] if not killRibbon.aggregate(tmpRibbon): filteredRibbons.append(tmpRibbon) filteredRibbons.append(tmpRibbon) ribbons[rType] = filteredRibbons excludedRibbons = dict( ((t, ribbons[t]) for t in _RIBBON_TYPES_EXCLUDED_IF_KILL_RIBBON if t in ribbons)) for rType, tmpRibbons in excludedRibbons.iteritems(): filteredRibbons = [ r for r in tmpRibbons if r.getVehicleID() not in killRibbons ] ribbons[rType] = filteredRibbons return ribbons def __getSortedList(self, ribbons): def _sortKey(ribbon): return ribbon.getID() sortedRibons = [] if ribbons: killRibbons = ribbons.pop(BATTLE_EFFICIENCY_TYPES.DESTRUCTION, None) detectionRibbons = ribbons.pop(BATTLE_EFFICIENCY_TYPES.DETECTION, None) if detectionRibbons is not None: sortedRibons.extend(sorted(detectionRibbons, key=_sortKey)) remaningRibbons = [] for newRibbons in ribbons.itervalues(): remaningRibbons.extend(newRibbons) sortedRibons.extend(sorted(remaningRibbons, key=_sortKey)) if killRibbons is not None: sortedRibons.extend(sorted(killRibbons, key=_sortKey)) return sortedRibons
class BrowserController(IBrowserController): _BROWSER_TEXTURE = 'BrowserBg' _ALT_BROWSER_TEXTURE = 'AltBrowserBg' def __init__(self): super(BrowserController, self).__init__() self.__browsers = {} self.__browsersCallbacks = {} self.__browserIDGenerator = SequenceIDGenerator() self.__eventMgr = Event.EventManager() self.onBrowserAdded = Event.Event(self.__eventMgr) self.onBrowserDeleted = Event.Event(self.__eventMgr) self.__urlMacros = URLMarcos() self.__pendingBrowsers = {} self.__creatingBrowserID = None self.__filters = _getGlobalFilters() return def fini(self): self.__filters = None self.__eventMgr.clear() self.__eventMgr = None self.__urlMacros.clear() self.__urlMacros = None self.__browserIDGenerator = None super(BrowserController, self).fini() return def onAvatarBecomePlayer(self): self.__stop() def onDisconnected(self): self.__stop() def addFilterHandler(self, handler): """ Adds given @handler to the browser urls filter chain. Calls it if there is a @tag in url onto opened browser page. Handler should receive url and list of client-specific tags, return bool as flag that routine have to stop """ self.__filters.add(handler) def removeFilterHandler(self, handler): """ Remove given @handler from filtering chain. Handler description can be seen in addFilterhandler method doc-string """ self.__filters.discard(handler) @async @process def load(self, url=None, title=None, showActionBtn=True, showWaiting=True, browserID=None, isAsync=False, browserSize=None, isDefault=True, callback=None, showCloseBtn=False, useBrowserWindow=True): url = yield self.__urlMacros.parse(url or GUI_SETTINGS.browser.url) suffix = yield self.__urlMacros.parse(GUI_SETTINGS.browser.params) concatenator = '&' if '?' in url else '?' if suffix not in url: url = concatenator.join([url, suffix]) size = browserSize or BROWSER.SIZE webBrowserID = browserID if browserID is None: browserID = self.__browserIDGenerator.next() webBrowserID = browserID elif type(browserID) is not int: webBrowserID = self.__browserIDGenerator.next() ctx = { 'url': url, 'title': title, 'showActionBtn': showActionBtn, 'showWaiting': showWaiting, 'browserID': browserID, 'size': size, 'isAsync': isAsync, 'showCloseBtn': showCloseBtn, 'showWindow': useBrowserWindow } texture = browserID not in self.__browsers and browserID not in self.__pendingBrowsers and self._BROWSER_TEXTURE app = g_appLoader.getApp() if not app: raise AssertionError('Application can not be None') browser = WebBrowser(webBrowserID, app, texture, size, url, handlers=self.__filters) self.__browsers[browserID] = browser if self.__isCreatingBrowser(): self.__pendingBrowsers[browserID] = ctx else: self.__createBrowser(ctx) elif browserID in self.__pendingBrowsers: self.__pendingBrowsers[browserID] = ctx elif browserID in self.__browsers: self.__browsers[browserID].navigate(url) callback(browserID) return def getBrowser(self, browserID): return self.__browsers.get(browserID) def delBrowser(self, browserID): if browserID in self.__browsers: browser = self.__browsers.pop(browserID) loadStart, loadEnd = self.__browsersCallbacks.pop( browserID, (None, None)) if loadStart is not None: browser.onLoadStart -= loadStart if loadEnd is not None: browser.onLoadEnd -= loadEnd browser.destroy() if self.__creatingBrowserID == browserID: self.__creatingBrowserID = None self.__tryCreateNextPendingBrowser() self.onBrowserDeleted(browserID) return def __isCreatingBrowser(self): return self.__creatingBrowserID is not None def __createDone(self, ctx): self.__creatingBrowserID = None g_eventBus.handleEvent( BrowserEvent(BrowserEvent.BROWSER_CREATED, ctx=ctx)) self.__tryCreateNextPendingBrowser() return def __tryCreateNextPendingBrowser(self): if len(self.__pendingBrowsers) > 0: nextCtx = self.__pendingBrowsers.popitem()[1] self.__createBrowser(nextCtx) def __createBrowser(self, ctx): browserID = ctx['browserID'] self.__creatingBrowserID = browserID self.__browsers[browserID].create() self.onBrowserAdded(browserID) def browserCallback(url, isLoaded): self.__clearCallback(browserID) if isLoaded: self.__showBrowser(browserID, ctx) else: LOG_WARNING('Browser request url was not loaded!', url) self.__createDone(browserID) if ctx['isAsync']: self.__browsersCallbacks[browserID] = (None, browserCallback) self.__browsers[browserID].onLoadEnd += browserCallback else: self.__browsersCallbacks[browserID] = (browserCallback, None) self.__browsers[browserID].onReady += browserCallback return def __stop(self): while self.__browsers: browserID, browser = self.__browsers.popitem() ready, loadEnd = self.__browsersCallbacks.pop( browserID, (None, None)) if ready is not None: browser.onReady -= ready if loadEnd is not None: browser.onLoadEnd -= loadEnd browser.destroy() return def __clearCallback(self, browserID): ready, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None)) if ready is not None: self.__browsers[browserID].onReady -= ready if loadEnd is not None: self.__browsers[browserID].onLoadEnd -= loadEnd return def __showBrowser(self, browserID, ctx): if ctx.get('showWindow'): g_eventBus.handleEvent( LoadViewEvent(VIEW_ALIAS.BROWSER_WINDOW, getViewName(VIEW_ALIAS.BROWSER_WINDOW, browserID), ctx=ctx), EVENT_BUS_SCOPE.LOBBY)
class BrowserController(IBrowserController): _BROWSER_TEXTURE = 'BrowserBg' _ALT_BROWSER_TEXTURE = 'AltBrowserBg' def __init__(self): super(BrowserController, self).__init__() self.__browsers = {} self.__browsersCallbacks = {} self.__browserCreationCallbacks = {} self.__browserIDGenerator = SequenceIDGenerator() self.__eventMgr = Event.EventManager() self.onBrowserAdded = Event.Event(self.__eventMgr) self.onBrowserDeleted = Event.Event(self.__eventMgr) self.__urlMacros = URLMarcos() self.__pendingBrowsers = {} self.__creatingBrowserID = None self.__filters = _getGlobalFilters() return def fini(self): self.__filters = None self.__eventMgr.clear() self.__eventMgr = None self.__urlMacros.clear() self.__urlMacros = None self.__browsersCallbacks.clear() self.__browsersCallbacks = None self.__browsers.clear() self.__browsers = None self.__pendingBrowsers.clear() self.__pendingBrowsers = None self.__browserIDGenerator = None super(BrowserController, self).fini() return def onAvatarBecomePlayer(self): self.__stop() def onDisconnected(self): self.__stop() def addFilterHandler(self, handler): self.__filters.add(handler) def removeFilterHandler(self, handler): self.__filters.discard(handler) @async @process def load(self, url=None, title=None, showActionBtn=True, showWaiting=True, browserID=None, isAsync=False, browserSize=None, isDefault=True, callback=None, showCloseBtn=False, useBrowserWindow=True, isModal=False, showCreateWaiting=False, handlers=None, showBrowserCallback=None, isSolidBorder=False): if showCreateWaiting: Waiting.show('browser/init') url = yield self.__urlMacros.parse(url or GUI_SETTINGS.browser.url) suffix = yield self.__urlMacros.parse(GUI_SETTINGS.browser.params) concatenator = '&' if '?' in url else '?' if suffix not in url: url = concatenator.join([url, suffix]) size = browserSize or BROWSER.SIZE webBrowserID = browserID if browserID is None: browserID = self.__browserIDGenerator.next() webBrowserID = browserID elif type(browserID) is not int: webBrowserID = self.__browserIDGenerator.next() ctx = {'url': url, 'title': title, 'showActionBtn': showActionBtn, 'showWaiting': showWaiting, 'browserID': browserID, 'size': size, 'isAsync': isAsync, 'showCloseBtn': showCloseBtn, 'showWindow': useBrowserWindow, 'alias': VIEW_ALIAS.BROWSER_WINDOW_MODAL if isModal else VIEW_ALIAS.BROWSER_WINDOW, 'showCreateWaiting': showCreateWaiting, 'handlers': handlers, 'showBrowserCallback': showBrowserCallback, 'isSolidBorder': isSolidBorder} if browserID not in self.__browsers and browserID not in self.__pendingBrowsers: texture = self._BROWSER_TEXTURE app = g_appLoader.getApp() if app is None: raise SoftException('Application can not be None') browser = WebBrowser(webBrowserID, app, texture, size, url, handlers=self.__filters) self.__browsers[browserID] = browser if self.__isCreatingBrowser(): _logger.debug('CTRL: Queueing a browser creation: %r - %s', browserID, url) self.__pendingBrowsers[browserID] = ctx else: self.__createBrowser(ctx) elif browserID in self.__pendingBrowsers: _logger.debug('CTRL: Re-queuing a browser creation, overriding: %r - %s', browserID, url) self.__pendingBrowsers[browserID] = ctx elif browserID in self.__browsers: _logger.debug('CTRL: Re-navigating an existing browser: %r - %s', browserID, url) browser = self.__browsers[browserID] browser.navigate(url) browser.changeTitle(title) callback(browserID) return def getAllBrowsers(self): return self.__browsers def getBrowser(self, browserID): return self.__browsers.get(browserID) def delBrowser(self, browserID): if browserID in self.__browsers: _logger.debug('CTRL: Deleting a browser: %s', browserID) browser = self.__browsers.pop(browserID) self.__clearCallbacks(browserID, browser, True) browser.destroy() if self.__creatingBrowserID == browserID: self.__creatingBrowserID = None self.__tryCreateNextPendingBrowser() if browserID in self.__pendingBrowsers: del self.__pendingBrowsers[browserID] self.onBrowserDeleted(browserID) return def __isCreatingBrowser(self): return self.__creatingBrowserID is not None def __createDone(self, ctx): _logger.debug('CTRL: Finished creating a browser: %s', self.__creatingBrowserID) if ctx['showCreateWaiting']: Waiting.hide('browser/init') def __tryCreateNextPendingBrowser(self): self.__creatingBrowserID = None if self.__pendingBrowsers: nextCtx = self.__pendingBrowsers.popitem()[1] self.__createBrowser(nextCtx) return def __createBrowser(self, ctx): browserID = ctx['browserID'] _logger.debug('CTRL: Creating a browser: %r - %s', browserID, ctx['url']) self.__creatingBrowserID = browserID browser = self.__browsers[browserID] if not browser.create(): _logger.debug('CTRL: Failed the create step: %r', browserID) self.delBrowser(browserID) self.__tryCreateNextPendingBrowser() return else: self.onBrowserAdded(browserID) def createBrowserTimeout(): _logger.debug('CTRL: Browser create timed out') createNextBrowser() timeoutid = BigWorld.callback(30.0, createBrowserTimeout) def createNextBrowser(): _logger.debug('CTRL: Triggering create of next browser from: %s', browserID) BigWorld.cancelCallback(timeoutid) creation = self.__browserCreationCallbacks.pop(browserID, None) if creation is not None: self.__browsers[browserID].onCanCreateNewBrowser -= creation BigWorld.callback(1.0, self.__tryCreateNextPendingBrowser) return def failedCreationCallback(url): _logger.debug('CTRL: Failed a creation: %r - %s', browserID, url) self.__clearCallbacks(browserID, self.__browsers[browserID], False) self.delBrowser(browserID) def successfulCreationCallback(url, isLoaded, httpStatusCode=None): _logger.debug('CTRL: Ready to show: %r - %r - %s', browserID, isLoaded, url) self.__clearCallbacks(browserID, self.__browsers[browserID], False) if isLoaded: self.__showBrowser(browserID, ctx) else: _logger.warning('Browser request url %s was not loaded!', url) g_eventBus.handleEvent(BrowserEvent(BrowserEvent.BROWSER_CREATED, ctx=ctx)) self.__createDone(ctx) def titleUpdateCallback(title): ctx['title'] = title browser.onCanCreateNewBrowser += createNextBrowser self.__browserCreationCallbacks[browserID] = createNextBrowser browser.onFailedCreation += failedCreationCallback browser.onTitleChange += titleUpdateCallback if ctx['isAsync']: self.__browsersCallbacks[browserID] = (None, successfulCreationCallback, failedCreationCallback, titleUpdateCallback) browser.onLoadEnd += successfulCreationCallback else: self.__browsersCallbacks[browserID] = (successfulCreationCallback, None, failedCreationCallback, titleUpdateCallback) browser.onReady += successfulCreationCallback return def __stop(self): while self.__browsers: browserID, browser = self.__browsers.popitem() self.__clearCallbacks(browserID, browser, True) browser.destroy() def __clearCallbacks(self, browserID, browser, incDelayedCreation): ready, loadEnd, failed, title = self.__browsersCallbacks.pop(browserID, (None, None, None, None)) if browser is not None: if failed is not None: browser.onFailedCreation -= failed if ready is not None: browser.onReady -= ready if loadEnd is not None: browser.onLoadEnd -= loadEnd if title is not None: browser.onTitleChange -= title if incDelayedCreation: creation = self.__browserCreationCallbacks.pop(browserID, None) if browser is not None and creation is not None: browser.onCanCreateNewBrowser -= creation return def __showBrowser(self, browserID, ctx): _logger.debug('CTRL: Showing a browser: %r - %s', browserID, ctx['url']) if ctx.get('showWindow'): alias = ctx['alias'] g_eventBus.handleEvent(LoadViewEvent(alias, getViewName(alias, browserID), ctx=ctx), EVENT_BUS_SCOPE.LOBBY) showBrowserCallback = ctx.get('showBrowserCallback') if showBrowserCallback: showBrowserCallback()
class InvitesManager(UsersInfoHelper): __clanInfo = None itemsCache = dependency.descriptor(IItemsCache) sessionProvider = dependency.descriptor(IBattleSessionProvider) lobbyContext = dependency.descriptor(ILobbyContext) def __init__(self, loader): super(InvitesManager, self).__init__() self.__loader = loader self._IDGen = SequenceIDGenerator() self._IDMap = {} self.__invites = {} self.__unreadInvitesCount = 0 self.__eventManager = Event.EventManager() self.__acceptChain = None self.onInvitesListInited = Event.Event(self.__eventManager) self.onReceivedInviteListModified = Event.Event(self.__eventManager) self.onSentInviteListModified = Event.Event(self.__eventManager) self.__isInBattle = False return def __del__(self): LOG_DEBUG('InvitesManager deleted') super(InvitesManager, self).__del__() def init(self): self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED g_messengerEvents.users.onUsersListReceived += self.__me_onUsersListReceived g_playerEvents.onPrebattleInvitesChanged += self.__pe_onPrebattleInvitesChanged g_playerEvents.onPrebattleInvitationsChanged += self.__pe_onPrebattleInvitationsChanged g_playerEvents.onPrebattleInvitesStatus += self.__pe_onPrebattleInvitesStatus def fini(self): self.__clearAcceptChain() self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED self.__loader = None g_messengerEvents.users.onUsersListReceived -= self.__me_onUsersListReceived g_playerEvents.onPrebattleInvitationsChanged -= self.__pe_onPrebattleInvitationsChanged g_playerEvents.onPrebattleInvitesChanged -= self.__pe_onPrebattleInvitesChanged g_playerEvents.onPrebattleInvitesStatus -= self.__pe_onPrebattleInvitesStatus self.clear() return def start(self): self.__isInBattle = False if self.__inited & PRB_INVITES_INIT_STEP.STARTED == 0: self.__inited |= PRB_INVITES_INIT_STEP.STARTED if self.__inited == PRB_INVITES_INIT_STEP.INITED: self.onInvitesListInited() def clear(self): self.__inited = PRB_INVITES_INIT_STEP.UNDEFINED self.__clearInvites() self._IDMap = {} self.__eventManager.clear() def onAvatarBecomePlayer(self): if self.__inited & PRB_INVITES_INIT_STEP.STARTED == 0: self.__inited |= PRB_INVITES_INIT_STEP.STARTED if self.__inited == PRB_INVITES_INIT_STEP.INITED: self.onInvitesListInited() self.__isInBattle = True self.__clearAcceptChain() @storage_getter('users') def users(self): return None def isInited(self): return self.__inited == PRB_INVITES_INIT_STEP.INITED def acceptInvite(self, inviteID, postActions = None): try: invite = self.__invites[inviteID] except KeyError: LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap) return self.__clearAcceptChain() if not postActions: invite.accept() else: self.__acceptChain = _AcceptInvitesPostActions(invite, postActions) self.__acceptChain.onStopped += self.__accept_onPostActionsStopped self.__acceptChain.start() if self.__unreadInvitesCount > 0: self.__unreadInvitesCount -= 1 def declineInvite(self, inviteID): try: invite = self.__invites[inviteID] except KeyError: LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap) return invite.decline() if self.__unreadInvitesCount > 0: self.__unreadInvitesCount -= 1 def revokeInvite(self, inviteID): try: invite = self.__invites[inviteID] except KeyError: LOG_ERROR('Invite ID is invalid', inviteID, self._IDMap) return invite.revoke() if self.__unreadInvitesCount > 0: self.__unreadInvitesCount -= 1 def canAcceptInvite(self, invite): result = False if invite.alwaysAvailable is True: result = True elif invite.clientID in self.__invites: dispatcher = self.__loader.getDispatcher() if dispatcher: if invite.alreadyJoined: return False if dispatcher.getEntity().hasLockedState(): return False another = invite.anotherPeriphery if another: if g_preDefinedHosts.periphery(invite.peripheryID) is None: LOG_ERROR('Periphery not found') result = False elif self.lobbyContext.getCredentials() is None: LOG_ERROR('Login info not found') result = False elif g_preDefinedHosts.isRoamingPeriphery(invite.peripheryID) and not isRoamingEnabled(self.itemsCache.items.stats.attributes): LOG_ERROR('Roaming is not supported') result = False else: result = invite.clientID > 0 and invite.isActive() else: result = invite.clientID > 0 and invite.isActive() return result def canDeclineInvite(self, invite): result = False if invite.clientID in self.__invites: result = invite.clientID > 0 and invite.isActive() return result def canRevokeInvite(self, invite): result = False if invite.clientID in self.__invites: result = invite.clientID > 0 and invite.isActive() and invite.creatorDBID == getPlayerDatabaseID() return result def getInvites(self, incoming = None, version = None, onlyActive = None): result = self.__invites.values() if incoming is not None: result = filter(lambda item: item.isIncoming() is incoming, result) if version is not None: result = filter(lambda item: item.getVersion() == version, result) if onlyActive is not None: result = filter(lambda item: item.isActive() is onlyActive, result) return result def getInvite(self, inviteID): invite = None if inviteID in self.__invites: invite = self.__invites[inviteID] return invite def getReceivedInviteCount(self): return len(self.getReceivedInvites()) def getReceivedInvites(self, IDs = None): result = self.getInvites(incoming=True) if IDs is not None: result = filter(lambda item: item.clientID in IDs, result) return result def getSentInvites(self, IDs = None): result = self.getInvites(incoming=False) if IDs is not None: result = filter(lambda item: item.clientID in IDs, result) return result def getSentInviteCount(self): return len(self.getSentInvites()) def getUnreadCount(self): return self.__unreadInvitesCount def resetUnreadCount(self): self.__unreadInvitesCount = 0 def onUserNamesReceived(self, names): updated = defaultdict(list) rosterGetter = self.users.getUser inviteMaker = self._getNewInviteMaker(rosterGetter) prebattleInvitations = _getNewInvites() for invite in self.getInvites(version=_INVITE_VERSION.NEW): if invite.creatorDBID in names or invite.receiverDBID in names: inviteUniqueId = UniqueId(id=invite.id, senderDBID=invite.creatorDBID) inviteData = prebattleInvitations.get(inviteUniqueId) inviteID, invite = inviteMaker(inviteData) if inviteData and self._updateInvite(invite, rosterGetter): updated[invite.isIncoming()].append(inviteID) for isIncoming, event in ((True, self.onReceivedInviteListModified), (False, self.onSentInviteListModified)): if updated[isIncoming]: event([], updated[isIncoming], []) def _makeInviteID(self, prebattleID, peripheryID, senderDBID, receiverDBID): inviteKey = (prebattleID, peripheryID, senderDBID, receiverDBID) inviteID = self._IDMap.get(inviteKey) if inviteID is None: inviteID = self._IDGen.next() self._IDMap[inviteKey] = inviteID return inviteID def _addInvite(self, invite, userGetter): if self.__isInviteSenderIgnoredInBattle(invite, userGetter): return False self.__invites[invite.clientID] = invite if invite.isActive(): self.__unreadInvitesCount += 1 return True def _updateInvite(self, other, userGetter): inviteID = other.clientID invite = self.__invites[inviteID] if invite == other or not invite.isActive() and self.__isInviteSenderIgnoredInBattle(invite, userGetter): return False prevCount = invite.count invite = invite._merge(other) self.__invites[inviteID] = invite if invite.isActive() and prevCount < invite.count: self.__unreadInvitesCount += 1 return True def _delInvite(self, inviteID): result = inviteID in self.__invites if result: self.__invites.pop(inviteID) return result def _buildReceivedInvitesList(self, invitesLists): if self.__inited & PRB_INVITES_INIT_STEP.DATA_BUILD == 0: self.__inited |= PRB_INVITES_INIT_STEP.DATA_BUILD self.__clearInvites() userGetter = self.users.getUser for invitesData, maker in invitesLists: for item in invitesData: _, invite = maker(item) if invite: self._addInvite(invite, userGetter) if g_appLoader.getSpaceID() != GUI_GLOBAL_SPACE_ID.BATTLE: self.syncUsersInfo() def _rebuildInvitesLists(self): rosterGetter = self.users.getUser self._buildReceivedInvitesList([(_getOldInvites().items(), self._getOldInviteMaker(rosterGetter)), (_getNewInvites().values(), self._getNewInviteMaker(rosterGetter))]) def _getOldInviteMaker(self, rosterGetter): receiver = getPlayerName() receiverDBID = getPlayerDatabaseID() receiverClanAbbrev = self.lobbyContext.getClanAbbrev(self.__clanInfo) def _inviteMaker(item): (prebattleID, peripheryID), data = item inviteID = self._makeInviteID(prebattleID, peripheryID, data['creatorDBID'], receiverDBID) if data is not None: invite = PrbInviteWrapper(clientID=inviteID, receiver=receiver, receiverDBID=receiverDBID, receiverClanAbbrev=receiverClanAbbrev, peripheryID=peripheryID, prebattleID=prebattleID, **data) else: invite = None return (inviteID, invite) return _inviteMaker def _getNewInviteMaker(self, rosterGetter): def _getUserName(userDBID): name, abbrev = ('', None) if userDBID: if g_appLoader.getSpaceID() == GUI_GLOBAL_SPACE_ID.BATTLE: ctx = self.sessionProvider.getCtx() isUserInBattle = ctx.getVehIDByAccDBID(userDBID) != 0 if isUserInBattle: name, abbrev = ctx.getPlayerFullNameParts(accID=userDBID, showVehShortName=False)[1:3] if not name: userName = self.getUserName(userDBID) userClanAbbrev = self.getUserClanAbbrev(userDBID) user = rosterGetter(userDBID) if user and user.hasValidName(): name, abbrev = userName, userClanAbbrev return (name, abbrev) def _inviteMaker(item): peripheryID, prebattleID = PrbInvitationWrapper.getPrbInfo(item.get('info', {})) senderDBID = item.get('senderDBID', 0) receiverDBID = item.get('receiverDBID', 0) inviteID = self._makeInviteID(prebattleID, peripheryID, senderDBID, receiverDBID) senderName, senderClanAbbrev = _getUserName(senderDBID) receiverName, receiverClanAbbrev = _getUserName(receiverDBID) return (inviteID, PrbInvitationWrapper(inviteID, sender=senderName, senderClanAbbrev=senderClanAbbrev, receiver=receiverName, receiverClanAbbrev=receiverClanAbbrev, **item)) return _inviteMaker def __initReceivedInvites(self): step = PRB_INVITES_INIT_STEP.CONTACTS_RECEIVED if self.__inited & step != step: return self._rebuildInvitesLists() if self.__inited == PRB_INVITES_INIT_STEP.INITED: self.onInvitesListInited() def __clearAcceptChain(self): if self.__acceptChain is not None: self.__acceptChain.onStopped -= self.__accept_onPostActionsStopped self.__acceptChain.stop() self.__acceptChain = None return def __me_onUsersListReceived(self, tags): doInit = False if USER_TAG.FRIEND in tags: doInit = True step = PRB_INVITES_INIT_STEP.FRIEND_RECEIVED if self.__inited & step == 0: self.__inited |= step if USER_TAG.IGNORED in tags or USER_TAG.IGNORED_TMP in tags: doInit = True step = PRB_INVITES_INIT_STEP.IGNORED_RECEIVED if self.__inited & step == 0: self.__inited |= step if doInit: self.__initReceivedInvites() def __pe_onPrebattleInvitesChanged(self, diff): step = PRB_INVITES_INIT_STEP.CONTACTS_RECEIVED if self.__inited & step != step: LOG_DEBUG('Received invites are ignored. Manager waits for client will receive contacts') return if ('prebattleInvites', '_r') in diff: self._rebuildInvitesLists() if 'prebattleInvites' in diff: self.__updateOldPrebattleInvites(_getOldInvites()) def __pe_onPrebattleInvitationsChanged(self, invitations): step = PRB_INVITES_INIT_STEP.CONTACTS_RECEIVED if self.__inited & step != step: LOG_DEBUG('Received invites are ignored. Manager waits for client will receive contacts') return self.__updateNewPrebattleInvites(invitations) def __pe_onPrebattleInvitesStatus(self, dbID, name, status): if status != PREBATTLE_INVITE_STATUS.OK: statusName = PREBATTLE_INVITE_STATUS_NAMES[status] SystemMessages.pushI18nMessage('#system_messages:invite/status/%s' % statusName, name=name, type=SystemMessages.SM_TYPE.Warning) def __updateOldPrebattleInvites(self, prbInvites): added = [] changed = [] deleted = [] modified = False rosterGetter = self.users.getUser inviteMaker = self._getOldInviteMaker(rosterGetter) for item in prbInvites.iteritems(): inviteID, invite = inviteMaker(item) if invite is None: if self._delInvite(inviteID): modified = True deleted.append(inviteID) continue inList = inviteID in self.__invites if not inList: if self._addInvite(invite, rosterGetter): modified = True added.append(inviteID) elif self._updateInvite(invite, rosterGetter): modified = True changed.append(inviteID) if modified: self.onReceivedInviteListModified(added, changed, deleted) return def __updateNewPrebattleInvites(self, prbInvites): added = defaultdict(list) changed = defaultdict(list) deleted = defaultdict(list) modified = dict(((v, False) for v in (True, False))) rosterGetter = self.users.getUser inviteMaker = self._getNewInviteMaker(rosterGetter) newInvites = {} for data in prbInvites.itervalues(): inviteID, invite = inviteMaker(data) if inviteID not in newInvites or invite.createTime > newInvites[inviteID].createTime: newInvites[inviteID] = invite for invite in self.getInvites(version=_INVITE_VERSION.NEW): inviteID = invite.clientID if inviteID not in newInvites and self._delInvite(inviteID): isIncoming = invite.isIncoming() modified[isIncoming] = True deleted[isIncoming].append(inviteID) else: continue for inviteID, invite in newInvites.iteritems(): isIncoming = invite.isIncoming() if inviteID not in self.__invites: if self._addInvite(invite, rosterGetter): modified[isIncoming] = True added[isIncoming].append(inviteID) elif self._updateInvite(invite, rosterGetter): modified[isIncoming] = True changed[isIncoming].append(inviteID) for isIncoming, event in ((True, self.onReceivedInviteListModified), (False, self.onSentInviteListModified)): if modified[isIncoming]: event(added[isIncoming], changed[isIncoming], deleted[isIncoming]) self.syncUsersInfo() def __accept_onPostActionsStopped(self, isCompleted): if not isCompleted: return invite = self.__acceptChain.invite invite.accept() if self.__unreadInvitesCount > 0: self.__unreadInvitesCount -= 1 def __clearInvites(self): self.__invites.clear() self.__unreadInvitesCount = 0 def __isInviteSenderIgnoredInBattle(self, invite, userGetter): return isInviteSenderIgnoredInBattle(userGetter(invite.creatorDBID), g_settings.userPrefs.invitesFromFriendsOnly, invite.isCreatedInBattle())
class BWChatProvider(object): __slots__ = ('__weakref__', '__handlers', '__msgFilters', '__coolDown', '__idGen', '__isEnabled', '__queue') def __init__(self): super(BWChatProvider, self).__init__() self.__handlers = defaultdict(set) self.__msgFilters = None self.__coolDown = _ChatCooldownManager() self.__idGen = SequenceIDGenerator() self.__isEnabled = False self.__queue = [] return def clear(self): self.__handlers.clear() BattleReplay.g_replayCtrl.delDataCallback( _REPLAY_ACTION_RECEIVED_CALLBACK, self.__onActionReceivedFromReplay) def goToReplay(self): BattleReplay.g_replayCtrl.setDataCallback( _REPLAY_ACTION_RECEIVED_CALLBACK, self.__onActionReceivedFromReplay) def setEnable(self, value): if self.__isEnabled == value: return self.__isEnabled = value if self.__isEnabled: self.__sendActionsFromQueue() else: self.__queue = [] def doAction(self, actionID, args=None, response=False, skipCoolDown=False): success, reqID = False, 0 if self.__coolDown.isInProcess(actionID): if not skipCoolDown: g_messengerEvents.onErrorReceived( createCoolDownError(actionID)) else: if response: reqID = self.__idGen.next() if self.__isEnabled: success = self.__sendAction(actionID, reqID, args) else: success = self.__addActionToQueue(actionID, reqID, args) return (success, reqID) def onActionReceived(self, actionID, reqID, args): if BattleReplay.g_replayCtrl.isRecording and self.__isActionWrittenToReplay( actionID): BattleReplay.g_replayCtrl.serializeCallbackData( _REPLAY_ACTION_RECEIVED_CALLBACK, (actionID, reqID, args)) handlers = self.__handlers[actionID] for handler in handlers: try: handler((actionID, reqID), args) except TypeError: LOG_ERROR('Handler has been invoked with error', handler) LOG_CURRENT_EXCEPTION() def setFilters(self, msgFilterChain): self.__msgFilters = msgFilterChain def filterInMessage(self, message): text = self.__msgFilters.chainIn(message.accountDBID, message.text) if not text: result = None else: message.text = text result = message return result def filterOutMessage(self, text, limits): return self.__msgFilters.chainOut(text, limits) def setActionCoolDown(self, actionID, coolDown): self.__coolDown.process(actionID, coolDown) def isActionInCoolDown(self, actionID): return self.__coolDown.isInProcess(actionID) def getActionCoolDown(self, actionID): return self.__coolDown.getTime(actionID) def clearActionCoolDown(self, actionID): self.__coolDown.reset(actionID) def registerHandler(self, actionID, handler): handlers = self.__handlers[actionID] if handler in handlers: LOG_WARNING('Handler already is exist', actionID, handler) else: if not hasattr(handler, '__self__') or not isinstance( handler.__self__, ActionsHandler): LOG_ERROR('Class of handler is not subclass of ActionsHandler', handler) return if callable(handler): handlers.add(handler) else: LOG_ERROR('Handler is invalid', handler) def unregisterHandler(self, actionID, handler): handlers = self.__handlers[actionID] if handler in handlers: handlers.remove(handler) def __sendAction(self, actionID, reqID, args=None): player = BigWorld.player() if not player: LOG_ERROR('Player is not defined') return False player.base.messenger_onActionByClient_chat2(actionID, reqID, args or messageArgs()) return True def __addActionToQueue(self, actionID, reqID, args=None): self.__queue.append((actionID, reqID, args)) return True def __sendActionsFromQueue(self): invokedIDs = set() while self.__queue: actionID, reqID, args = self.__queue.pop() if actionID in invokedIDs: LOG_WARNING( 'Action is ignored, your must send action after event "showGUI" is invoked', actionID, reqID, args) continue self.__sendAction(actionID, reqID, args) invokedIDs.add(actionID) @staticmethod def __isActionWrittenToReplay(actionID): return actionID == _ACTIONS.INIT_BATTLE_CHAT or _ACTIONS.battleChatCommandFromActionID( actionID) is not None def __onActionReceivedFromReplay(self, actionID, reqID, args): self.onActionReceived(actionID, reqID, args)
class SortiesCache(object): __selectedID = (0, 0) __rosterTypeID = 0 def __init__(self, controller): self.__controller = weakref.proxy(controller) self.__idGen = SequenceIDGenerator() self.__cache = {} self.__idToIndex = {} self.__indexToID = {} self.__selectedUnit = None self.__isRequestInProcess = False self.__cooldownRequest = None return def __del__(self): LOG_DEBUG('Sortie cache deleted:', self) def clear(self): self.__controller = None self.__cache.clear() self.__idToIndex.clear() self.__indexToID.clear() self.__selectedUnit = None if self.__cooldownRequest is not None: BigWorld.cancelCallback(self.__cooldownRequest) self.__cooldownRequest = None return def start(self): fort = self.__controller.getFort() if fort: fort.onSortieChanged += self.__fort_onSortieChanged fort.onSortieRemoved += self.__fort_onSortieRemoved fort.onSortieUnitReceived += self.__fort_onSortieUnitReceived self.__cache = self.__buildCache() else: LOG_ERROR('Client fort is not found') def stop(self): fort = self.__controller.getFort() if fort: fort.onSortieChanged -= self.__fort_onSortieChanged fort.onSortieRemoved -= self.__fort_onSortieRemoved fort.onSortieUnitReceived -= self.__fort_onSortieUnitReceived self.clear() def setController(self, controller): self.__controller = weakref.proxy(controller) @property def isRequestInProcess(self): return self.__isRequestInProcess @classmethod def getSelectedID(cls): return cls.__selectedID def clearSelectedID(self): self.__selectedUnit = None self._setSelectedID((0, 0)) return def setSelectedID(self, selectedID): if selectedID not in self.__cache: LOG_WARNING('Item is not found in cache', selectedID) return False else: self.__selectedUnit = None self._setSelectedID(selectedID) if BigWorld.player().isLongDisconnectedFromCenter: self.__controller._listeners.notify('onSortieUnitReceived', self.__getClientIdx(selectedID)) return True unit = self.getSelectedUnit() if unit and not self.__cache[selectedID]._isDirty: self.__controller._listeners.notify('onSortieUnitReceived', self.__getClientIdx(selectedID)) else: self._requestSortieUnit(selectedID) return True @classmethod def getRosterTypeID(cls): return cls.__rosterTypeID def setRosterTypeID(self, rosterTypeID): result = self._setRosterTypeID(rosterTypeID) if result: self.__cache = self.__buildCache() return result def getItem(self, sortieID): try: item = self.__cache[sortieID] except KeyError: LOG_ERROR('Item not found in cache', sortieID) item = None return item def getUnitByIndex(self, index): unit = None if index in self.__indexToID: sortieID = self.__indexToID[index] unit = self.__getUnit(sortieID) return unit def getSelectedUnit(self): return self.__getUnit(self.getSelectedID()) def getIterator(self): for item in self.__cache.itervalues(): if item.filter(self.__rosterTypeID): yield item def _requestSortieUnit(self, selectedID): Waiting.show('fort/sortie/get') if self.__cooldownRequest is not None: Waiting.hide('fort/sortie/get') BigWorld.cancelCallback(self.__cooldownRequest) self.__cooldownRequest = None ctx = RequestSortieUnitCtx(waitingID='', *selectedID) def requester(): self.__cooldownRequest = None self.__isRequestInProcess = True self.__controller.request(ctx, self.__requestCallback) return if self.__controller._cooldown.isInProcess(ctx.getRequestType()): self.__cooldownRequest = BigWorld.callback(self.__controller._cooldown.getTime(ctx.getRequestType()), requester) else: requester() return @classmethod def _setSelectedID(cls, selectedID): result = False if selectedID != cls.__selectedID and len(selectedID) == 2: cls.__selectedID = selectedID result = True return result @classmethod def _setRosterTypeID(cls, rosterTypeID): result = False if rosterTypeID != cls.__rosterTypeID: cls.__rosterTypeID = rosterTypeID result = True return result @classmethod def _removeStoredData(cls): cls.__selectedID = (0, 0) cls.__rosterTypeID = 0 def __buildCache(self): cache = {} fort = self.__controller.getFort() if not fort: LOG_WARNING('Client fort is not found') return cache sorties = fort.getSorties() selectedID = self.getSelectedID() found = False for sortieID, sortie in sorties.iteritems(): item = SortieItem(sortieID, sortie) if not found and item.getID() == selectedID: found = True cache[sortieID] = item if not found: self.clearSelectedID() return cache def __updateItem(self, sortieID, fort): sortie = fort.getSortieShortData(*sortieID) if sortie is None: LOG_ERROR('Sortie is not found', sortieID, fort.sorties) return else: if sortieID in self.__cache: item = self.__cache[sortieID] item._updateItemData(sortie) if item._isDirty and self.__selectedID == item.getID() and item.filter(self.getRosterTypeID()): self.__selectedUnit = None self._requestSortieUnit(sortieID) else: item = SortieItem(sortieID, sortie) self.__cache[sortieID] = item return item def __requestCallback(self, _): Waiting.hide('fort/sortie/get') self.__isRequestInProcess = False def __removeItem(self, sortieID): result = False if sortieID in self.__cache: self.__cache.pop(sortieID) result = True if self.getSelectedID() == sortieID: self.clearSelectedID() clientIdx = self.__idToIndex.pop(sortieID, None) if clientIdx is not None: self.__indexToID.pop(clientIdx, None) return result def __getClientIdx(self, sortieID): if sortieID == (0, 0): return 0 if sortieID not in self.__idToIndex: clientIdx = self.__idGen.next() self.__idToIndex[sortieID] = clientIdx self.__indexToID[clientIdx] = sortieID else: clientIdx = self.__idToIndex[sortieID] return clientIdx def __getUnit(self, sortieID): fort = self.__controller.getFort() if not fort: LOG_WARNING('Client fort is not found') return else: isSelected = self.getSelectedID() == sortieID if isSelected and self.__selectedUnit is not None: return self.__selectedUnit unit = fort.getSortieUnit(*sortieID) if isSelected: self.__selectedUnit = unit return unit def __fort_onSortieChanged(self, unitMgrID, peripheryID): fort = self.__controller.getFort() sortieID = (unitMgrID, peripheryID) if fort: item = self.__updateItem(sortieID, fort) if item: self.__controller._listeners.notify('onSortieChanged', self, item) def __fort_onSortieRemoved(self, unitMgrID, peripheryID): sortieID = (unitMgrID, peripheryID) if self.__removeItem(sortieID): self.__controller._listeners.notify('onSortieRemoved', self, sortieID) def __fort_onSortieUnitReceived(self, unitMgrID, peripheryID): fort = self.__controller.getFort() sortieID = (unitMgrID, peripheryID) if fort: if unitMgrID in self.__cache: self.__cache[sortieID]._isDirty = False if self.getSelectedID() == sortieID: self.__selectedUnit = None self.__controller._listeners.notify('onSortieUnitReceived', self.__getClientIdx(sortieID)) return
class BrowserController(Controller): _BROWSER_TEXTURE = 'BrowserBg' _ALT_BROWSER_TEXTURE = 'AltBrowserBg' def __init__(self, proxy): super(BrowserController, self).__init__(proxy) self.__browsers = {} self.__browsersCallbacks = {} self.__browserIDGenerator = SequenceIDGenerator() self.__eventMgr = Event.EventManager() self.onBrowserAdded = Event.Event(self.__eventMgr) self.onBrowserDeleted = Event.Event(self.__eventMgr) self.__urlMacros = URLMarcos() self.__pendingBrowsers = {} self.__creatingBrowserID = None self.__filters = _getGlobalFilters() return def fini(self): self.__filters = None self.__eventMgr.clear() self.__eventMgr = None self.__urlMacros.clear() self.__urlMacros = None self.__browserIDGenerator = None super(BrowserController, self).fini() return def onAvatarBecomePlayer(self): self.__stop() def onDisconnected(self): self.__stop() def addFilterHandler(self, handler): """ Adds given @handler to the browser urls filter chain. Calls it if there is a @tag in url onto opened browser page. Handler should receive url and list of client-specific tags, return bool as flag that routine have to stop """ self.__filters.add(handler) def removeFilterHandler(self, handler): """ Remove given @handler from filtering chain. Handler description can be seen in addFilterhandler method doc-string """ self.__filters.discard(handler) @async @process def load(self, url = None, title = None, showActionBtn = True, showWaiting = True, browserID = None, isAsync = False, browserSize = None, isDefault = True, callback = None, showCloseBtn = False, useBrowserWindow = True): url = yield self.__urlMacros.parse(url or GUI_SETTINGS.browser.url) suffix = yield self.__urlMacros.parse(GUI_SETTINGS.browser.params) concatenator = '&' if '?' in url else '?' if suffix not in url: url = concatenator.join([url, suffix]) size = browserSize or BROWSER.SIZE webBrowserID = browserID if browserID is None: browserID = self.__browserIDGenerator.next() webBrowserID = browserID elif type(browserID) is not int: webBrowserID = self.__browserIDGenerator.next() ctx = {'url': url, 'title': title, 'showActionBtn': showActionBtn, 'showWaiting': showWaiting, 'browserID': browserID, 'size': size, 'isAsync': isAsync, 'showCloseBtn': showCloseBtn, 'showWindow': useBrowserWindow} texture = browserID not in self.__browsers and browserID not in self.__pendingBrowsers and self._BROWSER_TEXTURE app = g_appLoader.getApp() if not app: raise AssertionError('Application can not be None') browser = WebBrowser(webBrowserID, app, texture, size, url, handlers=self.__filters) self.__browsers[browserID] = browser if self.__isCreatingBrowser(): self.__pendingBrowsers[browserID] = ctx else: self.__createBrowser(ctx) elif browserID in self.__pendingBrowsers: self.__pendingBrowsers[browserID] = ctx elif browserID in self.__browsers: self.__browsers[browserID].navigate(url) callback(browserID) return def getBrowser(self, browserID): return self.__browsers.get(browserID) def delBrowser(self, browserID): if browserID in self.__browsers: browser = self.__browsers.pop(browserID) loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None)) if loadStart is not None: browser.onLoadStart -= loadStart if loadEnd is not None: browser.onLoadEnd -= loadEnd browser.destroy() if self.__creatingBrowserID == browserID: self.__creatingBrowserID = None self.__tryCreateNextPendingBrowser() self.onBrowserDeleted(browserID) return def __isCreatingBrowser(self): return self.__creatingBrowserID is not None def __createDone(self, ctx): self.__creatingBrowserID = None g_eventBus.handleEvent(BrowserEvent(BrowserEvent.BROWSER_CREATED, ctx=ctx)) self.__tryCreateNextPendingBrowser() return def __tryCreateNextPendingBrowser(self): if len(self.__pendingBrowsers) > 0: nextCtx = self.__pendingBrowsers.popitem()[1] self.__createBrowser(nextCtx) def __createBrowser(self, ctx): browserID = ctx['browserID'] self.__creatingBrowserID = browserID self.__browsers[browserID].create() self.onBrowserAdded(browserID) def browserCallback(url, isLoaded): self.__clearCallback(browserID) if isLoaded: self.__showBrowser(browserID, ctx) else: LOG_WARNING('Browser request url was not loaded!', url) self.__createDone(browserID) if ctx['isAsync']: self.__browsersCallbacks[browserID] = (None, browserCallback) self.__browsers[browserID].onLoadEnd += browserCallback else: self.__browsersCallbacks[browserID] = (browserCallback, None) self.__browsers[browserID].onReady += browserCallback return def __stop(self): while self.__browsers: browserID, browser = self.__browsers.popitem() ready, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None)) if ready is not None: browser.onReady -= ready if loadEnd is not None: browser.onLoadEnd -= loadEnd browser.destroy() return def __clearCallback(self, browserID): ready, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None)) if ready is not None: self.__browsers[browserID].onReady -= ready if loadEnd is not None: self.__browsers[browserID].onLoadEnd -= loadEnd return def __showBrowser(self, browserID, ctx): if ctx.get('showWindow'): g_eventBus.handleEvent(LoadViewEvent(VIEW_ALIAS.BROWSER_WINDOW, getViewName(VIEW_ALIAS.BROWSER_WINDOW, browserID), ctx=ctx), EVENT_BUS_SCOPE.LOBBY)
class FortBattlesCache(object): __selectedID = 0 def __init__(self, controller): self.__controller = weakref.proxy(controller) self.__idGen = SequenceIDGenerator() self.__cache = {} self.__idToIndex = {} self.__indexToID = {} self.__selectedUnit = None self.__isRequestInProcess = False return def __del__(self): LOG_DEBUG('Fort battles cache deleted:', self) def clear(self): self.__controller = None self.__cache.clear() self.__idToIndex.clear() self.__indexToID.clear() self.__selectedUnit = None return def start(self): fort = self.__controller.getFort() if fort: fort.onFortBattleChanged += self.__fort_onFortBattleChanged fort.onFortBattleRemoved += self.__fort_onFortBattleRemoved fort.onFortBattleUnitReceived += self.__fort_onFortBattleUnitReceived fort.onEnemyStateChanged += self.__fort_onEnemyStateChanged self.__cache = self.__buildCache() else: LOG_ERROR('Client fort is not found') def stop(self): fort = self.__controller.getFort() if fort: fort.onFortBattleChanged -= self.__fort_onFortBattleChanged fort.onFortBattleRemoved -= self.__fort_onFortBattleRemoved fort.onFortBattleUnitReceived -= self.__fort_onFortBattleUnitReceived fort.onEnemyStateChanged -= self.__fort_onEnemyStateChanged self.clear() @property def isRequestInProcess(self): return self.__isRequestInProcess @classmethod def getSelectedID(cls): return cls.__selectedID def getSelectedIdx(self): return self.__getClientIdx(self.getSelectedID()) def clearSelectedID(self): self.__selectedUnit = None self._setSelectedID(0) return def setSelectedID(self, selectedID): if selectedID not in self.__cache: LOG_WARNING('Item is not found in cache', selectedID) return False else: self.__selectedUnit = None return self._setSelectedID(selectedID) def getItem(self, battleID): try: item, fortBattle = self.__cache[battleID] except KeyError: LOG_ERROR('Item not found in cache', battleID) item = None fortBattle = None return (item, fortBattle) def getUnitByIndex(self, index): unit = None if index in self.__indexToID: battleID = self.__indexToID[index] unit = self.__getUnit(battleID) return unit def getSelectedUnit(self): return self.__getUnit(self.getSelectedID()) def getIterator(self): for item, battleItem in self.__cache.itervalues(): if item.filter(): yield (item, battleItem) @classmethod def _setSelectedID(cls, selectedID): result = False if selectedID != cls.__selectedID: cls.__selectedID = selectedID result = True return result @classmethod def _removeStoredData(cls): cls.__selectedID = (0, 0) def __buildCache(self): cache = {} fort = self.__controller.getFort() if not fort: LOG_WARNING('Client fort is not found') return cache fortBattles = fort.getAttacksAndDefencesIn(timePeriod=2 * time_utils.ONE_WEEK) selectedID = self.getSelectedID() found = False for item in fortBattles: battleID = item.getBattleID() if not found and battleID == selectedID: found = True battleItem = fort.getBattle(battleID) cache[battleID] = (item, battleItem) if not found: self.clearSelectedID() return cache def __updateItem(self, battleID, fort): item = fort.getBattleItemByBattleID(battleID) if item is None: LOG_ERROR('Fort battle is not found', battleID, fort.attacks, fort.defences) return (None, None) else: fortBattle = fort.getBattle(battleID) self.__cache[battleID] = (item, fortBattle) if self.getSelectedID() == battleID: self.__selectedUnit = None return (item, fortBattle) def __requestCallback(self, _): self.__isRequestInProcess = False def __removeItem(self, battleID): result = False if battleID in self.__cache: self.__cache.pop(battleID) result = True if self.getSelectedID() == battleID: self.clearSelectedID() clientIdx = self.__idToIndex.pop(battleID, None) if clientIdx is not None: self.__indexToID.pop(clientIdx, None) return result def __getClientIdx(self, battleID): if battleID == 0: return 0 if battleID not in self.__idToIndex: clientIdx = self.__idGen.next() self.__idToIndex[battleID] = clientIdx self.__indexToID[clientIdx] = battleID else: clientIdx = self.__idToIndex[battleID] return clientIdx def __getUnit(self, battleID): fort = self.__controller.getFort() if not fort: LOG_WARNING('Client fort is not found') return else: isSelected = battleID == self.getSelectedID() if isSelected and self.__selectedUnit is not None: return self.__selectedUnit unit = fort.getFortBattleUnit(battleID) if isSelected: self.__selectedUnit = unit return unit def __fort_onEnemyStateChanged(self, battleID, isReady): fort = self.__controller.getFort() if fort: item, battleItem = self.__updateItem(battleID, fort) if item: self.__controller._listeners.notify('onFortBattleChanged', self, item, battleItem) def __fort_onFortBattleChanged(self, battleID): fort = self.__controller.getFort() if fort: item, battleItem = self.__updateItem(battleID, fort) if item: self.__controller._listeners.notify('onFortBattleChanged', self, item, battleItem) def __fort_onFortBattleRemoved(self, battleID): if self.__removeItem(battleID): self.__controller._listeners.notify('onFortBattleRemoved', self, battleID) def __fort_onFortBattleUnitReceived(self, battleID): fort = self.__controller.getFort() if fort: if self.__selectedID == battleID: self.__selectedUnit = None self.__controller._listeners.notify('onFortBattleUnitReceived', self.__getClientIdx(battleID)) return
class BrowserController(Controller): _BROWSER_TEXTURE = 'BrowserBg' _ALT_BROWSER_TEXTURE = 'AltBrowserBg' def __init__(self, proxy): super(BrowserController, self).__init__(proxy) self.__browsers = {} self.__browsersCallbacks = {} self.__browserIDGenerator = SequenceIDGenerator() self.__eventMgr = Event.EventManager() self.onBrowserAdded = Event.Event(self.__eventMgr) self.onBrowserDeleted = Event.Event(self.__eventMgr) self.__urlMacros = URLMarcos() self.__pendingBrowsers = {} self.__creatingBrowser = False def fini(self): self.__eventMgr.clear() self.__eventMgr = None self.__urlMacros.clear() self.__urlMacros = None self.__browserIDGenerator = None super(BrowserController, self).fini() return def onAvatarBecomePlayer(self): self.__stop() def onDisconnected(self): self.__stop() @async @process def load(self, url = None, title = None, showActionBtn = True, showWaiting = True, browserID = None, isAsync = False, browserSize = None, isDefault = True, callback = None, showCloseBtn = False, useWhitelisting = False): url = yield self.__urlMacros.parse(url or GUI_SETTINGS.browser.url) suffix = yield self.__urlMacros.parse(GUI_SETTINGS.browser.params) concatenator = '&' if '?' in url else '?' if suffix not in url: url = concatenator.join([url, suffix]) size = browserSize or BROWSER.SIZE webBrowserID = browserID if browserID is None: browserID = self.__browserIDGenerator.next() webBrowserID = browserID elif type(browserID) is not int: webBrowserID = self.__browserIDGenerator.next() ctx = {'url': url, 'title': title, 'showActionBtn': showActionBtn, 'showWaiting': showWaiting, 'browserID': browserID, 'size': size, 'isDefault': isDefault, 'isAsync': isAsync, 'showCloseBtn': showCloseBtn} texture = browserID not in self.__browsers and browserID not in self.__pendingBrowsers and (self._BROWSER_TEXTURE if isDefault else self._ALT_BROWSER_TEXTURE) app = g_appLoader.getApp() if not app: raise AssertionError('Application can not be None') browser = WebBrowser(webBrowserID, app, texture, size, url, useWhitelisting) self.__browsers[browserID] = browser if self.__creatingBrowser: self.__pendingBrowsers[browserID] = ctx else: self.__createBrowser(ctx) elif browserID in self.__pendingBrowsers: self.__pendingBrowsers[browserID] = ctx elif browserID in self.__browsers: self.__browsers[browserID].navigate(url) callback(browserID) return def __createDone(self, browserID): self.__creatingBrowser = False if len(self.__pendingBrowsers) > 0: ctx = self.__pendingBrowsers.popitem()[1] self.__createBrowser(ctx) def __createBrowser(self, ctx): self.__creatingBrowser = True browserID = ctx['browserID'] self.__browsers[browserID].create() self.onBrowserAdded(browserID) def browserCallback(*args): self.__clearCallback(browserID) self.__showBrowser(browserID, ctx) self.__createDone(browserID) def browserAsyncCallback(url, isLoaded): self.__clearCallback(browserID) if isLoaded: self.__showBrowser(browserID, ctx) else: LOG_WARNING('Browser async request url was not loaded!', url) self.__createDone(browserID) if ctx['isAsync']: self.__browsersCallbacks[browserID] = (None, browserAsyncCallback) self.__browsers[browserID].onLoadEnd += browserAsyncCallback else: self.__browsersCallbacks[browserID] = (browserCallback, None) self.__browsers[browserID].onReady += browserCallback return def getBrowser(self, browserID): return self.__browsers.get(browserID) def delBrowser(self, browserID): if browserID in self.__browsers: browser = self.__browsers.pop(browserID) loadStart, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None)) if loadStart is not None: browser.onLoadStart -= loadStart if loadEnd is not None: browser.onLoadEnd -= loadEnd browser.destroy() self.onBrowserDeleted(browserID) return def __stop(self): while self.__browsers: browserID, browser = self.__browsers.popitem() ready, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None)) if ready is not None: browser.onReady -= ready if loadEnd is not None: browser.onLoadEnd -= loadEnd browser.destroy() return def __clearCallback(self, browserID): ready, loadEnd = self.__browsersCallbacks.pop(browserID, (None, None)) if ready is not None: self.__browsers[browserID].onReady -= ready if loadEnd is not None: self.__browsers[browserID].onLoadEnd -= loadEnd return def __showBrowser(self, browserID, ctx): g_eventBus.handleEvent(LoadViewEvent(VIEW_ALIAS.BROWSER_WINDOW, getViewName(VIEW_ALIAS.BROWSER_WINDOW, browserID), ctx=ctx), EVENT_BUS_SCOPE.LOBBY)
class MarathonRewardWindowView(ViewImpl): eventsCache = dependency.descriptor(IEventsCache) marathonController = dependency.descriptor(IMarathonEventsController) c11n = dependency.descriptor(ICustomizationService) itemsCache = dependency.descriptor(IItemsCache) def __init__(self, ctx, *args, **kwargs): settings = ViewSettings(R.views.lobby.marathon.RewardWindow()) settings.flags = ViewFlags.VIEW settings.model = MarathonPrizeRewardModel() super(MarathonRewardWindowView, self).__init__(settings, *args, **kwargs) self.__rewards = [] self.__convertRewards(ctx) self.__marathon = self.marathonController.getMarathon(ctx.get('marathonPrefix')) self.__idGen = SequenceIDGenerator() self.__bonusCache = {} @property def viewModel(self): return super(MarathonRewardWindowView, self).getViewModel() def createToolTipContent(self, event, contentID): if event.contentID == R.views.lobby.marathon.tooltips.RestRewardTooltip() and len(self.__rewards) > MAX_REWARDS_COUNT: restRewards = self.__rewards[MAX_REWARDS_COUNT:] formatterRewards = self.__formatterRewards(restRewards, False) return MarathonRewardTooltipContent(formatterRewards) return super(MarathonRewardWindowView, self).createToolTipContent(event, contentID) def createToolTip(self, event): tooltipId = event.getArgument('tooltipId') if not tooltipId: return super(MarathonRewardWindowView, self).createToolTip(event) bonus = self.__bonusCache.get(tooltipId) if bonus: window = BackportTooltipWindow(createTooltipData(tooltip=bonus.tooltip, isSpecial=bonus.isSpecial, specialAlias=bonus.specialAlias, specialArgs=bonus.specialArgs), self.getParentWindow()) window.load() return window return super(MarathonRewardWindowView, self).createToolTip(event) def _onLoading(self, *args, **kwargs): super(MarathonRewardWindowView, self)._onLoading(*args, **kwargs) with self.viewModel.transaction() as model: self._fillModel(model) def _initialize(self, *args, **kwargs): super(MarathonRewardWindowView, self)._initialize(*args, **kwargs) self._addListeners() def _finalize(self): self._removeListeners() self.__bonusCache.clear() super(MarathonRewardWindowView, self)._finalize() def _addListeners(self): self.viewModel.onAcceptClicked += self._onAccepted self.viewModel.onCancelClicked += self._onCancel self.viewModel.onSecondaryClicked += self._onSecondary def _removeListeners(self): self.viewModel.onAcceptClicked -= self._onAccepted self.viewModel.onCancelClicked -= self._onCancel self.viewModel.onSecondaryClicked -= self._onSecondary def _getVehicleObtainedTitle(self): current, last = self.__marathon.getMarathonProgress() if current == 0: return R.strings.marathon.reward.stageAllComplete() return R.strings.marathon.reward.stageNotAllComplete() if current < last else R.strings.marathon.reward.stageCompleteLast() def _fillModel(self, model): isMainProgressionReward = not self.__marathon.isPostRewardObtained() vehicle = self.__marathon.vehicle self._fillRewards(model) if isMainProgressionReward: stage = 1 suptitle = self._getVehicleObtainedTitle() model.setSupTitle(suptitle) model.setTitle(R.strings.marathon.reward.vehicleTitle()) model.setSubTitle(R.strings.marathon.reward.nameVehicle()) model.setImage(_ICON_PATH.vehicle_image_cn() if IS_CHINA else _ICON_PATH.vehicle_image()) model.vehicle.setName(vehicle.userName) model.vehicle.setType(vehicle.type) model.vehicle.setLevel(vehicle.level) else: stage = 2 model.setSupTitle(R.strings.marathon.reward.stageStyle()) model.setTitle(R.strings.marathon.reward.styleTitle()) model.setSubTitle(R.strings.marathon.reward.nameStyle()) model.setImage(_ICON_PATH.style_image_cn() if IS_CHINA else _ICON_PATH.style_image()) model.setIconReward(_ICON_PATH.style_reward()) model.setHasVehicle(isMainProgressionReward) model.setStage(stage) def _onAccepted(self, *args): self.destroyWindow() if not self.__marathon.isPostRewardObtained(): selectVehicleInHangar(self.__marathon.vehicle.compactDescr) def _onCancel(self): self.destroyWindow() def _onSecondary(self): if self.__marathon.vehicle.isInInventory: self.c11n.showCustomization(self.__marathon.vehicle.invID) else: style = self.c11n.getItemByID(GUI_ITEM_TYPE.STYLE, self.__marathon.styleID) showStylePreview(self.__marathon.vehicle.compactDescr, style, style.getDescription(), showHangar) def _fillRewards(self, model): rewardsCount = len(self.__rewards) if rewardsCount > MAX_REWARDS_COUNT: rewards = self.__rewards[:MAX_REWARDS_COUNT] restRewardsCount = rewardsCount - MAX_REWARDS_COUNT model.setRewards(self.__formatterRewards(rewards, True)) model.setRestRewardsCount(restRewardsCount) else: model.setRewards(self.__formatterRewards(self.__rewards, True)) model.setRestRewardsCount(0) def __formatterRewards(self, rewards, addTooltip=False): results = Array() for reward in rewards: model = BonusModel() model.setName(reward.bonusName) model.setIcon(getRewardImage(reward.images['big'])) model.setLabel(getRewardLabel(reward.label)) model.setOverlayType(getRewardOverlayType(reward.overlayType)) if addTooltip: self.__setTooltip(model, reward) else: model.setDescription(reward.userName) results.addViewModel(model) return results def __setTooltip(self, model, reward): tooltipId = '{}'.format(self.__idGen.next()) self.__bonusCache[tooltipId] = reward model.setTooltipId(tooltipId) def __sortRewardsByPriority(self, rewards, priority=REWARDS_PRIORITY, defaultPriority=len(REWARDS_PRIORITY)): rewards.sort(key=lambda x: self.__sortRewardsFunc(x, priority, defaultPriority)) return rewards def __sortRewardsFunc(self, bonus, priority, defaultPriority): name = bonus.getName() if name == 'items': epicBonusList = bonus.getWrappedEpicBonusList() if epicBonusList: id_ = epicBonusList[0]['id'] name = self.itemsCache.items.getItemByCD(id_).itemTypeName return priority.index(name) if name in priority else defaultPriority def __convertRewards(self, ctx): self.__rewards = ctx.get('rewards', []) self.__rewards = splitBonuses(self.__rewards) crewRewards = ctx.get('crewRewards', None) if crewRewards: self.__rewards.append(crewRewards) self.__rewards = self.__sortRewardsByPriority(self.__rewards) formatter = getMarathonRewardScreenPacker() self.__rewards = formatter.format(self.__rewards) return