Example #1
0
    async def _handle_message(self, message: str) -> None:
        """Handle received messages.

        :param message: The message to parse.
        :type message: str
        """
        try:
            # Showdown websocket messages are pipe-separated sequences
            split_messages = [m.split("|") for m in message.split("\n")]
            # The type of message is determined by the first entry in the message
            # For battles, this is the zero-th entry
            # Otherwise it is the one-th entry
            if split_messages[0][0].startswith(">battle"):
                # Battle update
                await self._handle_battle_message(split_messages)
            elif split_messages[0][1] == "challstr":
                # Confirms connection to the server: we can login
                await self._log_in(split_messages[0])
            elif split_messages[0][1] == "updateuser":
                if split_messages[0][2] == " " + self._username:
                    # Confirms successful login
                    self.logged_in.set()
                elif not split_messages[0][2].startswith(" Guest "):
                    self.logger.warning(
                        """Trying to login as %s, showdown returned %s """
                        """- this might prevent future actions from this agent. """
                        """Changing the agent's username might solve this problem.""",
                        self.username,
                        split_messages[0][2],
                    )
            elif "updatechallenges" in split_messages[0][1]:
                # Contain information about current challenge
                await self._update_challenges(split_messages[0])
            elif split_messages[0][1] == "updatesearch":
                pass
            elif split_messages[0][1] == "popup":
                self.logger.warning("Popup message received: %s", message)
            elif split_messages[0][1] in ["nametaken"]:
                self.logger.critical("Error message received: %s", message)
                raise ShowdownException("Error message received: %s", message)
            elif split_messages[0][1] == "pm":
                assert len(split_messages) == 1
                if split_messages[0][4].startswith("/challenge"):
                    await self._handle_challenge_request(split_messages[0])
                elif split_messages[0][4].startswith("/text"):
                    self.logger.info("Received pm with text: %s", message)
                else:
                    self.logger.warning("Received pm: %s", message)
            else:
                self.logger.warning("Unhandled message: %s", message)
        except CancelledError as e:
            self.logger.critical("CancelledError intercepted: %s", e)
        except Exception as exception:
            self.logger.exception(
                "Unhandled exception raised while handling message:\n%s",
                message)
            raise exception
Example #2
0
 def accuracy(self) -> float:
     """
     :return: The move's accuracy (0 to 1 scale).
     :rtype: float
     """
     accuracy = self.entry["accuracy"]
     if isinstance(accuracy, int):
         return accuracy / 100
     if accuracy is True:
         return 1
     raise ShowdownException("Unmanaged accuracy: %s", accuracy)
Example #3
0
    def from_request_details(gender: str) -> "PokemonGender":
        """Returns the PokemonGenre object corresponding to the gender received in a message.

        :param gender: The received gender to convert.
        :type gender: str
        :return: The corresponding PokemonGenre object.
        :rtype: PokemonGenre
        """
        if gender == "M":
            return PokemonGender.MALE
        elif gender == "F":
            return PokemonGender.FEMALE
        raise ShowdownException("Unmanaged request gender: '%s'", gender)
Example #4
0
    async def _create_battle(self, split_message: List[str]) -> AbstractBattle:
        """Returns battle object corresponding to received message.

        :param split_message: The battle initialisation message.
        :type split_message: List[str]
        :return: The corresponding battle object.
        :rtype: AbstractBattle
        """
        # We check that the battle has the correct format
        if split_message[1] == self._format and len(split_message) >= 2:
            # Battle initialisation
            battle_tag = "-".join(split_message)[1:]

            if battle_tag in self._battles:
                return self._battles[battle_tag]
            else:
                if self.format_is_doubles:
                    battle = DoubleBattle(
                        battle_tag=battle_tag,
                        username=self.username,
                        logger=self.logger,
                        save_replays=self._save_replays,
                    )
                else:
                    battle = Battle.from_format(
                        format_=self._format,
                        battle_tag=battle_tag,
                        username=self.username,
                        logger=self.logger,
                        save_replays=self._save_replays,
                    )
                await self._battle_count_queue.put(None)
                if battle_tag in self._battles:
                    self._battle_count_queue.get()
                    return self._battles[battle_tag]
                async with self._battle_start_condition:
                    self._battle_semaphore.release()
                    self._battle_start_condition.notify_all()
                    self._battles[battle_tag] = battle

                if self._start_timer_on_battle_start:
                    await self._send_message("/timer on", battle.battle_tag)

                return battle

            return self._battles[battle_tag]
        else:
            self.logger.critical(
                "Unmanaged battle initialisation message received: %s", split_message
            )
            raise ShowdownException()
Example #5
0
    async def _create_battle(self, split_message: List[str]) -> Battle:
        """Returns battle object corresponding to received message.

        :param split_message: The battle initialisation message.
        :type split_message: List[str]
        :return: The corresponding battle object.
        :rtype: Battle
        """
        # We check that the battle has the correct format
        if split_message[1] == self._format and len(split_message) >= 2:
            # Battle initialisation
            battle_tag = "-".join(split_message)
            if battle_tag.startswith(">"):
                battle_tag = battle_tag[1:]
            if battle_tag.endswith("\n"):
                battle_tag = battle_tag[:-1]

            if battle_tag in self._battles:
                return self._battles[battle_tag]
            else:
                battle = Battle(battle_tag=battle_tag,
                                username=self.username,
                                logger=self.logger)
                await self._battle_started_callback(battle)

                await self._battle_count_queue.put(None)
                if battle_tag in self._battles:
                    self._battle_count_queue.get()
                    return self._battles[battle_tag]
                async with self._battle_start_condition:
                    self._battle_semaphore.release()
                    self._battle_start_condition.notify_all()
                    self._battles[battle_tag] = battle
                return battle

            return self._battles[battle_tag]
        else:
            self.logger.critical(
                "Unmanaged battle initialisation message received: %s",
                split_message)
            raise ShowdownException()
Example #6
0
    async def _handle_message(self, message: str) -> None:
        """Handle received messages.

        :param message: The message to parse.
        :type message: str
        """
        try:
            self.logger.debug("Received message to handle: %s", message)

            # Showdown websocket messages are pipe-separated sequences
            split_message = message.split("|")
            assert len(split_message) > 1
            # The type of message is determined by the first entry in the message
            # For battles, this is the zero-th entry
            # Otherwise it is the one-th entry
            if split_message[1] == "challstr":
                # Confirms connection to the server: we can login
                await self._log_in(split_message)
            elif (split_message[1] == "updateuser"
                  and split_message[2] == " " + self._username):
                # Confirms successful login
                self.logged_in.set()
            elif "updatechallenges" in split_message[1]:
                # Contain information about current challenge
                await self._update_challenges(split_message)
            elif split_message[0].startswith(">battle"):
                # Battle update
                await self._handle_battle_message(message)
            elif split_message[1] in ["updatesearch", "popup", "updateuser"]:
                self.logger.debug("Ignored message: %s", message)
                pass
            elif split_message[1] in ["nametaken"]:
                self.logger.critical("Error message received: %s", message)
                raise ShowdownException("Error message received: %s", message)
            elif split_message[1] == "pm":
                self.logger.info("Received pm: %s", split_message)
            else:
                self.logger.critical("Unhandled message: %s", message)
                raise NotImplementedError("Unhandled message: %s" % message)
        except CancelledError:
            pass