def pm(self, room, sender, receiver, *message): user = User(sender[1:], sender[0], self.isOwner(sender)) if self.userIsSelf(user.id): return message = '|'.join(message) if message.startswith('/invite'): if not message[8:] == 'lobby': if user.hasRank('+'): self.joinRoom(message[8:]) self.log('Invite', message, user.id) else: self.sendPm(user.id, 'Only global voices (+) and up can add me to rooms, sorry :(') if message.startswith(self.commandchar) and message[1:] and (message[1].isalpha() or message[1] == '!'): command = self.extractCommand(message) self.log('Command', message, user.id) params = message[len(command) + len(self.commandchar):].lstrip() response = self.invoker.execute(self, command, params, user, Room('pm')) if not response.text or response.text == 'NoAnswer': return self.sendPm(user.id, response.text)
def handleJoin(self, room, message): """ Handles new users entering a room. Args: room: Room object, room this message was received from. message: string, string produced from user joining this room. Returns: None. Raises: None. """ if room.loading: return if self.userIsSelf(message[1:]): room.rank = message[0] room.doneLoading() user = User(message, message[0], self.isOwner(message)) if not room.addUser(user): return self.takeAction( room.title, user, 'roomban', "You are blacklisted from this room, so please don't come here." )
def handleJoin(self, room, message): """ Handles new users entering a room. Args: room: Room object, room this message was received from. message: string, string produced from user joining this room. Returns: None. Raises: None. """ if self.userIsSelf(message[1:]): room.rank = message[0] room.doneLoading() user = User(message, message[0], self.isOwner(message)) if not room.addUser(user): return self.takeAction(room.title, user, 'roomban', "You are blacklisted from this room, so please don't come here.") # If the user have a message waiting, tell them that in a pm if self.usernotes.shouldNotifyMessage(user.id): self.sendPm(user.id, self.usernotes.pendingMessages(user.id))
def parseMessage(self, msg, roomName): """Parses the message given by a user and delegates the tasks further This is where we handle the parsing of all the non-battle related PS protocols. Tasks like user related queries (i.e. commands) are delegated to the Command method. And Showdown tournaments are handled in their own handler in the plugins module. Likewise for the MessageDatabase interface. Args: msg: String, string produced from interacting with the websocket connected to the PS server. Example: "|c:|1467521329| bb8nu|random chat message". roomName: String, name of the room that the message came from. Returns: None. Raises: None. """ if not msg.startswith('|'): return message = self.escapeMessage(msg).split('|') room = self.getRoom(roomName) # we got messages from a room we aren't in? if not room: if not roomName: room = Room('Empty') else: self.rooms[roomName] = Room(roomName) # Logging in if message[1] == 'challstr': print('{name}: Attempting to login...'.format(name=self.name)) self.login(message[3], message[2]) elif message[1] == 'updateuser': self.updateUser(message[2], message[3]) # Challenges elif 'updatechallenges' in message[1]: challs = json.loads(message[2]) if challs['challengesFrom']: opp = [ name for name, form in challs['challengesFrom'].items() ][0] format = challs['challengesFrom'][opp] if format in self.bh.supportedFormats: team = self.bh.getRandomTeam(format) self.send('|/utm {}'.format(team)) self.send('|/accept {name}'.format(name=opp)) else: self.sendPm( opp, "Sorry, I can't accept challenges in that format :(") elif 'updatesearch' in message[1]: # This gets sent before `updatechallenges` does when receiving a battle, but it's # not useful for anything, so just return straight away return # This is a safeguard for l and n in case that a moderation action happen elif 'unlink' == message[1] or 'uhtml' in message[ 1] or 'html' == message[1]: return # Room was left in some way other than through ~leave elif 'deinit' == message[1] and room: self.rooms.pop(room.title) elif 'popup' == message[1]: print(message[2].replace('||', '\n\t')) elif 'noinit' == message[1]: # we didn't join the room for some other reason (doesn't exist/roombanned) self.rooms.pop(room.title, None) # As long as the room have a roomintro (which even groupchats do now) # Roomintros are also the last thing that is sent when joining a room # so when this show up, assume the room is loaded elif 'raw' == message[1]: if message[2].startswith( '<div class="infobox infobox-roomintro"><div class="infobox-limited">' ): room.doneLoading() # Joined new room elif 'users' in message[1]: for user in message[2].split(',')[1:]: room.addUser(User(user[1:], user[0], self.isOwner(user))) # If PS doesn't tell us we joined, this still give us our room rank room.rank = message[2][message[2].index(self.name) - 1] elif 'j' in message[1].lower(): if room.loading: return self.handleJoin(room, message[2]) elif 'l' == message[1].lower() or 'leave' == message[1].lower(): if room.loading: return if self.userIsSelf(message[2][1:]): # This is just a failsafe in case the bot is forcibly removed from a room. # Any other memory release required is handeled by the room destruction if roomName in self.rooms: self.rooms.pop(room.title) return userid = self.toId(message[2]) room.removeUser(userid) elif 'n' in message[1].lower() and len(message[1]) < 3: if room.loading: return # Keep track of your own rank # When demoting / promoting a user the server sends a |N| message to update the userlist if self.userIsSelf(message[2][1:]): room.rank = message[2][0] newUser = User(message[2][1:], message[2][0], self.isOwner(message[2])) room.renamedUser(self.toId(message[3]), newUser) self.handleJoin(room, message[2]) # Chat messages elif 'c' in message[1].lower(): if room.isHistory(message): return user = room.getUser(self.toId(message[3])) if not user: return if self.userIsSelf(user.id): return room.logChat(user, message[4], message[2]) saidMessage = '|'.join(message[4:]) if saidMessage.startswith( self.commandchar) and saidMessage[1:] and ( saidMessage[1].isalpha() or saidMessage[1] == '!'): command = self.extractCommand(saidMessage) self.log('Command', saidMessage, user.id) res = self.invoker.execute( self, command, saidMessage[len(command) + 1:].lstrip(), user, room) if not res.text or res.text == 'NoAnswer': return if self.userHasPermission(user, self.details['broadcastrank'] ) or res.ignoreBroadcastPermission: if not res.ignoreEscaping: res.text = self.escapeText(res.text) self.reply(room.title, user, res.text, res.samePlace) elif res.canPmReply: self.sendPm(user.id, self.escapeText(res.text)) else: self.sendPm(user.id, 'Please pm the command for a response.') # Test room punishments after commands anything = room.moderation.shouldAct(message[4], user, message[2]) if anything and self.canPunish(room): action, reason = room.moderation.getAction( room, user, anything, message[2]) self.takeAction(room.title, user, action, reason) if type(room.activity) == Workshop: room.activity.logSession(room.title, user.rank + user.name, message[4]) elif 'pm' in message[1].lower(): user = User(message[2][1:], message[2][0], self.isOwner(message[2])) if self.userIsSelf(user.id): return if message[4].startswith('/invite'): if not message[4][8:] == 'lobby': if user.hasRank('+'): self.joinRoom(message[4][8:]) self.log('Invite', message[4], user.id) else: self.sendPm( user.id, 'Only global voices (+) and up can add me to rooms, sorry :(' ) message[4] = '|'.join(message[4:]) if message[4].startswith(self.commandchar) and message[4][1:] and ( message[4][1].isalpha() or message[4][1] == '!'): command = self.extractCommand(message[4]) self.log('Command', message[4], user.id) params = message[4][len(command) + len(self.commandchar):].lstrip() response = self.invoker.execute(self, command, params, user, Room('pm')) if not response.text or response.text == 'NoAnswer': return self.sendPm(user.id, response.text) # Tournaments elif 'tournament' == message[1]: if 'create' in message[2]: room.createTour(self.ws, message[3], self.bh) if room.loading: return # Tour was created, join it if in supported formats if self.details[ 'joinTours'] and room.tour.format in self.bh.supportedFormats: room.tour.joinTour() elif 'end' == message[2]: if not room.loading: winners, tier = room.getTourWinner(message[3]) if self.name in winners: message = 'I won the {form} tournament :o'.format( form=tier) if len(winners) > 1: winners.remove(self.name) message += '\nCongratulations to {others} for also winning :)'.format( others=', '.join(winners)) self.say(room.title, message) else: self.say( room.title, 'Congratulations to {name} for winning :)'.format( name=', '.join(winners))) room.endTour() elif 'forceend' in message[2]: room.endTour() else: # This is for general tournament updates if not room.tour or room.loading: return room.tour.onUpdate(message[2:])
def users(self, room, users): for user in users.split(',')[1:]: room.addUser(User(user[1:], user[0], self.isOwner(user))) # If PS doesn't tell us we joined, this still give us our room rank room.rank = users[users.index(self.name) - 1]
def parseMessage(self, msg, roomName): """Parses the message given by a user and delegates the tasks further This is where we handle the parsing of all the non-battle related PS protocols. Tasks like user related queries (i.e. commands) are delegated to the Command method. And Showdown tournaments are handled in their own handler in the plugins module. Likewise for the MessageDatabase interface. Args: msg: String, string produced from interacting with the websocket connected to the PS server. Example: "|c:|1467521329| bb8nu|random chat message". roomName: String, name of the room that the message came from. Returns: None. Raises: None. """ if not msg.startswith('|'): return message = self.escapeMessage(msg).split('|') room = Room('Empty') if not roomName else self.getRoom(roomName) # Logging in if message[1] == "challstr": print("{name}: Attempting to login...".format(name=self.name)) self.login(message[3], message[2]) elif message[1] == "updateuser": self.updateUser(message[2], message[3]) # Challenges elif "updatechallenges" in message[1]: challs = json.loads(message[2]) if challs['challengesFrom']: opp = [name for name, form in challs['challengesFrom'].items()][0] format = challs['challengesFrom'][opp] if format in self.bh.supportedFormats: team = self.bh.getRandomTeam(format) self.send('|/utm {}'.format(team)) self.send('|/accept {name}'.format(name=opp)) else: self.sendPm(opp, "Sorry, I can't accept challenges in that format :(") elif 'updatesearch' in message[1]: # This gets sent before `updatechallenges` does when receiving a battle, but it's # not useful for anything, so just return straight away return # This is a safeguard for l and n in case that a moderation action # happen elif("unlink" == message[1] or "uhtml" in message[1] or "html" == message[1]): return # Room was left in some way other than through ~leave elif 'deinit' == message[1]: self.rooms.pop(roomName) # As long as the room have a roomintro (which even groupchats do now) # Roomintros are also the last thing that is sent when joining a room # so when this show up, assume the room is loaded elif "raw" == message[1]: if message[2].startswith(('<div class="infobox infobox-roomintro">' '<div class="infobox-limited">')): room.doneLoading() # Joined new room elif 'users' in message[1]: for user in message[2].split(',')[1:]: room.addUser(User(user[1:], user[0], self.isOwner(user))) # If PS doesn't tell us we joined, this still give us our room rank room.rank = message[2][message[2].index(self.name) - 1] elif "j" in message[1].lower(): self.handleJoin(room, message[2]) elif "l" == message[1].lower() or "leave" == message[1].lower(): if self.userIsSelf(message[2][1:]): # This is just a failsafe in case the bot is forcibly removed # from a room. Any other memory release required is handeled by # the room destruction if roomName in self.rooms: self.rooms.pop(roomName) return userid = self.toId(message[2]) room.removeUser(userid) elif "n" in message[1].lower() and len(message[1]) < 3: # Keep track of your own rank # When demoting / promoting a user the server sends a |N| message # to update the userlist if self.userIsSelf(message[2][1:]): room.rank = message[2][0] newUser = User(message[2][1:], message[2][0], self.isOwner(message[2])) room.renamedUser(self.toId(message[3]), newUser) self.handleJoin(room, message[2]) # Chat messages elif "c" in message[1].lower(): if room.loading: return user = room.getUser(self.toId(message[3])) if not user: return if self.userIsSelf(user.id): return # perform moderation on user content room.logChat(user, message[2]) saidMessage = '|'.join(message[4:]) # this message follows the command structure i.e. '~send hi' if saidMessage.startswith(self.commandchar) and saidMessage[1:] and saidMessage[1].isalpha(): command = self.extractCommand(saidMessage) self.log('Command', saidMessage, user.id) res = self.do(self, command, room, saidMessage[len(command) + 1:].lstrip(), user) if not res.text or res.text == 'NoAnswer': return if self.userHasPermission(user, room.broadcast_rank) or res.ignoreBroadcastPermission: if not res.ignoreEscaping: res.text = self.escapeText(res.text) self.reply(room.title, user, res.text, res.samePlace) elif not self.userHasPermission(user, room.broadcast_rank): self.sendPm(user.id, 'You do not have broadcast rank, requires {}'.format(room.broadcast_rank)) elif res.canPmReply: self.sendPm(user.id, self.escapeText(res.text)) else: self.sendPm(user.id, 'Please pm the command for a response.') else: # this message should be considered to be any normal message found in chat self.learn(room, user, saidMessage) # Test room punishments after commands anything = room.moderation.shouldAct(message[4], user, message[2]) if anything and self.canPunish(room): action, reason = room.moderation.getAction(room, user, anything, message[2]) self.takeAction(room.title, user, action, reason) if type(room.activity) == Workshop: room.activity.logSession(room.title, user.rank + user.name, message[4]) elif 'pm' in message[1].lower(): user = User(message[2][1:], message[2][0], self.isOwner(message[2])) if self.userIsSelf(user.id): return if message[4].startswith("/invite"): if not message[4][8:] == "lobby": if user.hasRank("&"): self.joinRoom(message[4][8:]) self.log("Invite", message[4], user.id) else: self.sendPm(user.id, "Only global leaders (&) and up can add me to rooms, sorry :(") message[4] = '|'.join(message[4:]) if message[4].startswith(self.commandchar) and message[4][1:] and message[4][1].isalpha(): command = self.extractCommand(message[4]) self.log('Command', message[4], user.id) params = message[4][len(command) + len(self.commandchar):] params = params.lstrip() response = self.do(self, command, Room('pm'), params, user) if not response.text or response.text == 'NoAnswer': return self.sendPm(user.id, response.text) # Tournaments elif 'tournament' == message[1]: if 'create' in message[2]: room.createTour(self.ws, message[3], self.bh) if room.loading: return # Tour was created, join it if in supported formats if details.joinTours and room.tour.format in self.bh.supportedFormats: room.tour.joinTour() elif 'end' == message[2]: if not room.loading: winner, tier = room.getTourWinner(message[3]) if self.name in winner: self.say(room.title, 'I won the {form} tournament :o'.format(form=tier)) else: self.say(room.title, 'Congratulations to {name} for winning :)'.format(name=', '.join(winner))) room.endTour() elif "forceend" in message[2]: room.endTour() else: # This is for general tournament updates if not room.tour or room.loading: return room.tour.onUpdate(message[2:])
def parseMessage(self, msg, roomName): if not msg.startswith('|'): return message = msg.split('|') room = self.getRoom(roomName) # Logging in if message[1] == 'challstr': print('{name}: Attempting to login...'.format(name = self.name)) self.login(message[3], message[2]) elif message[1] == 'updateuser': self.updateUser(message[2], message[3]) # Challenges elif 'updatechallenges' in message[1]: challs = json.loads(message[2]) if challs['challengesFrom']: opp = [name for name, form in challs['challengesFrom'].items()][0] if challs['challengesFrom'][opp] in supportedFormats: self.send('|/accept {name}'.format(name = opp)) else: self.sendPm(opp, 'Sorry, I only accept challenges in Challenge Cup 1v1, Random Battles or Battle Factory :(') elif 'updatesearch' in message[1]: # This gets sent before `updatechallenges` does when recieving a battle, but it's # not useful for anything, so just return straight away return # This is a safeguard for l and n in case that a moderation action happen elif 'unlink' == message[1] or 'uhtml' in message[1] or 'html' == message[1]: return # As long as the room have a roomintro (whih even groupchats do now) # Roomintros are also the last thing that is sent when joining a room # so when this show up, assume the room is loaded elif 'raw' == message[1]: if message[2].startswith('<div class="infobox infobox-roomintro"><div class="infobox-limited">'): room.doneLoading() # Joined new room elif 'users' in message[1]: for user in message[2].split(',')[1:]: room.addUser(User(user[1:], user[0], True if self.isOwner(user[1:]) else False)) # If PS doesn't tell us we joined, this still give us our room rank room.rank = message[2][message[2].index(self.name) - 1] elif 'j' in message[1].lower(): self.handleJoin(room, message[2]) elif 'l' == message[1].lower() or 'leave' == message[1].lower(): if self.userIsSelf(message[2][1:]): # This is just a failsafe in case the bot is forcibly removed from a room. # Any other memory release required is handeled by the room destruction if roomName in self.rooms: self.rooms.pop(roomName) return userid = self.toId(message[2]) room.removeUser(userid) elif 'n' in message[1].lower() and len(message[1]) < 3: # Keep track of your own rank # When demoting / promoting a user the server sends a |N| message to update the userlist if self.userIsSelf(message[2][1:]): room.rank = message[2][0] oldName = self.toId(message[3]) room.renamedUser(oldName, User(message[2][1:], message[2][0])) # Chat messages elif 'c' in message[1].lower(): if room.loading: return user = room.getUser(self.toId(message[3])) if not user: return if self.userIsSelf(user.id): return if room.moderate and self.canPunish(room): anything = moderation.shouldAct(message[4], user, room, message[2]) if anything: action, reason = moderation.getAction(self, room, user, anything, message[2]) self.log('Action', action, user.id) self.takeAction(room.title, user.id, action, reason) if message[4].startswith(self.commandchar) and message[4][1:] and message[4][1].isalpha(): command = self.extractCommand(message[4]) self.log('Command', message[4], user.id) response, samePlace = '', True # If the command was a chat game and permissions aren't met, kill the game (even if it just started) if not room.allowGames and command in GameCommands: response = 'This room does not support chatgames.' else: response, samePlace = self.do(self, command, room, message[4][len(command) + 1:].lstrip(), user) if response == 'NoAnswer': return if self.evalPermission(user) or command in IgnoreBroadcastPermission: if command not in IgnoreEscaping: response = self.escapeText(response) self.reply(room.title, user, response, samePlace) elif command in CanPmReplyCommands: self.sendPm(user.id, self.escapeText(response)) else: self.sendPm(user.id, 'Please pm the commands for a response.') if type(room.game) == Workshop: room.game.logSession(room.title, user.rank + user.name, message[4]) elif 'pm' in message[1].lower(): user = User(message[2][1:], message[2][0], True if self.isOwner(self.toId(message[2])) else False) if self.userIsSelf(user.id): return if message[4].startswith('/invite'): if not message[4][8:] == 'lobby': if user.hasRank('+'): self.joinRoom(message[4][8:]) self.log('Invite', message[4], user.id) else: self.sendPm(user.id, 'Only global voices (+) and up can add me to rooms, sorry :(') if message[4].startswith(self.commandchar) and message[4][1:] and message[4][1].isalpha(): command = self.extractCommand(message[4]) self.log('Command', message[4], user.id) params = message[4][len(command) + len(self.commandchar):].lstrip() response = '' if command in GameCommands: if params.startswith('score'): response, where = self.do(self, command, Room('pm'), params, user) else: response = "Don't try to play games in pm please" if not response: response, where = self.do(self, command, Room('pm'), params, user) self.sendPm(user.id, response) # Tournaments elif 'tournament' == message[1]: if room.loading: return if 'create' in message[2]: if not room.tour: room.createTour(self.ws, message[3]) # Tour was created, join it if in supported formats if not self.details['joinTours']: return if room.tour and room.tour.format in supportedFormats: room.tour.joinTour() elif 'end' == message[2]: if not room.tour: return winner, tier = room.tour.getWinner(message[3]) if self.name in winner: self.say(room.title, 'I won the {form} tournament :o'.format(form = tier)) else: self.say(room.title, 'Congratulations to {name} for winning :)'.format(name = ', '.join(winner))) room.endTour() elif 'forceend' in message[2]: room.endTour() else: if room.tour: room.tour.onUpdate(message[2:])