Beispiel #1
0
class MemoryMonitor(threading.Thread):
    """Checks when COH1 game has started/ended."""

    def __init__(
        self,
        pollInterval=10,
        ircClient: IRC_Client = None,
        settings=None
                ):
        threading.Thread.__init__(self)
        try:
            logging.info("Memory Monitor Started!")
            self.running = True

            self.settings = settings
            if not settings:
                self.settings = Settings()

            self.pm = None
            self.baseAddress = None
            self.gameInProgress = False

            self.ircClient = ircClient
            self.pollInterval = int(pollInterval)
            self.event = threading.Event()
            self.gameData = None
            self.winLostTimer = None

        except Exception as e:
            logging.error("In FileMonitor __init__")
            logging.error(str(e))
            logging.exception("Exception : ")

    def run(self):
        try:
            while self.running:
                self.get_gamedata()
                if self.gameInProgress:

                    if self.gameData.gameInProgress != self.gameInProgress:
                        # coh was running and now its not (game over)
                        self.game_over()
                else:
                    if self.gameData.gameInProgress != self.gameInProgress:
                        # coh wasn't running and now it is (game started)
                        self.game_started()

                # set local gameInProgress flag to it can be compared with
                # any changes to it in the next loop
                self.gameInProgress = self.gameData.gameInProgress
                self.event.wait(self.pollInterval)
        except Exception as e:
            logging.error("In FileMonitor run")
            logging.error(str(e))
            logging.exception("Exception : ")

    def get_gamedata(self):
        try:
            self.gameData = GameData(
                ircClient=self.ircClient,
                settings=self.settings)
            self.gameData.get_data_from_game()
        except Exception as e:
            logging.error("In getGameData")
            logging.info(str(e))
            logging.exception("Exception : ")

    def game_started(self):
        try:
            self.gameData.output_opponent_data()
            # legacy posting of data to opponent bot channel
            self.post_steam_number()
            # enable to output to the opponent bot channel
            self.post_data()
            # enable to output to the opponent bot channel
            self.start_bets()
            # enable to set odds
            self.set_odds()

        except Exception as e:
            logging.info("Problem in GameStarted")
            logging.error(str(e))
            logging.exception("Exception : ")

    def post_steam_number(self):
        try:
            channel = str(self.settings.data.get('channel'))
            steamNumber = str(self.settings.data.get('steamNumber'))
            message = f"!setsteam,{channel},{steamNumber}"
            self.ircClient.send_message_to_opponentbot_channel(message)
        except Exception as e:
            logging.error("Problem in PostSteamNumber")
            logging.exception("Exception : ")
            logging.error(str(e))

    def post_data(self):
        # Sending to cohopponentbot channel about game,
        # this requires parsing mapName First
        try:
            message = self.gameData.get_game_description_string()
            self.ircClient.send_message_to_opponentbot_channel(message)

        except Exception as e:
            logging.error("Problem in PostData")
            logging.error(str(e))
            logging.exception("Exception : ")

    def game_over(self):
        try:
            # Get Win/Lose from server after 50 seconds
            # legacy can only be turned on by toggle in file
            # removed from GUI because server win / lose inconsistant
            # occasionally reports incorrectly therefore not worth using.
            # by default writeIWonLostInChat now set to False in file.
            if self.settings.data.get('writeIWonLostInChat'):
                self.winLostTimer = threading.Timer(50.0, self.get_win_lose)
                self.winLostTimer.start()
            # Clear the overlay
            if (self.settings.data.get('clearOverlayAfterGameOver')):
                self.ircClient.queue.put("CLEAROVERLAY")
        except Exception as e:
            logging.info("Problem in GameOver")
            logging.error(str(e))
            logging.exception("Exception : ")

    def get_win_lose(self):
        try:
            # legacy method for info only
            # match history doesn't always get updated immediately.
            # unknown delay or faulty server means can report incorrectly.
            # therefore not used, code kept for reference only.
            statnumber = self.settings.data.get('steamNumber')
            statRequest = StatsRequest(settings=self.settings)
            statRequest.get_match_history_from_server(statnumber)
            mostRecentWin = statRequest.get_player_win_last_match(statnumber)
            if mostRecentWin:
                self.ircClient.send_private_message_to_IRC("!I won")
            else:
                self.ircClient.send_private_message_to_IRC("!I lost")

        except Exception as e:
            logging.info("Problem in GetWinLose")
            logging.error(str(e))
            logging.exception("Exception : ")

    def start_bets(self):

        info = (
            f"Size of self.gameData.playerList "
            f"in StartBets {len(self.gameData.playerList)}"
        )
        logging.info(info)
        if (bool(self.settings.data.get('writePlaceYourBetsInChat'))):
            ps = ""
            outputList = []
            if self.gameData:
                if self.gameData.playerList:
                    if len(self.gameData.playerList) == 2:
                        # if two player make sure the streamer is put first
                        for player in self.gameData.playerList:
                            output = player.name
                            output += " "
                            output += player.faction.name
                            outputList.append(output)
                        # player list does not have steam numbers.
                        # Need to aquire these from warning.log
                        ps = f"{outputList[1]} Vs. {outputList[0]}"
                        pls = self.gameData.playerList[0].stats
                        if pls:
                            sn = str(self.settings.data.get('steamNumber'))
                            psn = str(pls.steamNumber)
                            if sn == psn:
                                ps = f"{outputList[0]} Vs. {outputList[1]}"

                    message = "!startbets {}".format(ps)
                    self.ircClient.send_private_message_to_IRC(message)

    def set_odds(self):
        if (bool(self.settings.data.get('automaticSetBettingOdds'))):
            if self.gameData:
                if self.gameData.playerList:
                    odds = 0.5
                    contenderTeamRatio = 0
                    opponentTeamRatio = 0
                    axisTeamList = []
                    alliesTeamList = []

                    for item in self.gameData.playerList:
                        if (
                            str(item.faction) == str(Faction.US)
                            or str(item.faction) == str(Faction.CW)
                        ):
                            if item.name != "":
                                alliesTeamList.append(item)
                        if (
                            str(item.faction) == str(Faction.WM)
                            or str(item.faction) == str(Faction.PE)
                        ):
                            if item.name != "":
                                axisTeamList.append(item)

                    team1List = []
                    team2List = []

                    # by default player team is allies unless
                    # the player is steam number is present in
                    # the axisTeamList
                    team1List = alliesTeamList
                    team2List = axisTeamList

                    for item in axisTeamList:
                        if item.stats:
                            steamNumber = str(
                                self.settings.data.get('steamNumber'))
                            if steamNumber == str(
                                    item.stats.steamNumber):
                                # logging.info ("Player team is AXIS")
                                team1List = axisTeamList
                                team2List = alliesTeamList
                    # The contender is now in team1List
                    for player in team1List:
                        for value in player.stats.leaderboardData:
                            matchType = str(
                                player.stats.leaderboardData[value].matchType)
                            if matchType == str(self.gameData.matchType):
                                faction = str(
                                    player.stats.leaderboardData[
                                        value].faction)
                                if faction == str(player.faction):
                                    contenderTeamRatio += (
                                        player.stats.leaderboardData[
                                            value].winLossRatio)

                    for player in team2List:
                        for value in player.stats.leaderboardData:
                            matchType = str(
                                player.stats.leaderboardData[value].matchType)
                            if matchType == str(self.gameData.matchType):
                                faction = str(
                                    player.stats.leaderboardData[
                                        value].faction)
                                if faction == str(player.faction):
                                    opponentTeamRatio += (
                                        player.stats.leaderboardData[
                                            value].winLossRatio)

                    try:
                        if opponentTeamRatio:
                            odds = (contenderTeamRatio / (
                                contenderTeamRatio + opponentTeamRatio))
                        else:
                            odds = 0.5
                    except Exception as e:
                        odds = 0.5
                        logging.error(str(e))
                        logging.exception("Exception : ")
                    message = f"!setodds {str(round(odds, 2))}"
                    self.ircClient.send_private_message_to_IRC(message)

    def close(self):
        logging.info("Memory Monitor Closing!")
        self.running = False
        # break out of loops if waiting
        if self.event:
            self.event.set()
        # if timer is running and program is closed then cancel the timer
        # and call getwinlose early. legacy timer.
        if self.winLostTimer:
            self.winLostTimer.cancel()
            # self.GetWinLose()

    def find_between(self, s, first, last):
        try:
            start = s.index(first) + len(first)
            end = s.index(last, start)
            return s[start:end]
        except ValueError:
            return ""
class IRC_Channel(threading.Thread):
    """Implements an IRC Channel Connection. Checks User Commands."""

    def __init__(
        self,
        ircClient,
        ircSocket: socket,
        queue,
        channel,
        settings=None
            ):
        Thread.__init__(self)
        self.ircClient = ircClient
        self.running = True
        self.ircSocket = ircSocket
        self.queue = queue
        self.channel = channel

        self.settings = settings
        if not settings:
            self.settings = Settings()

        self.gameData = GameData(self.ircClient, settings=self.settings)

    def run(self):
        self.ircSocket.send(('JOIN ' + self.channel + '\r\n').encode("utf8"))
        while self.running:
            line = self.queue.get()
            line = str.rstrip(line)
            line = str.split(line)
            if (line[0] == "EXITTHREAD"):
                self.close()
            if (line[0] == "OPPONENT"):
                self.check_for_user_command("self", "opp")
            if (line[0] == "TEST"):
                self.test_output()
            if (line[0] == "IWON"):
                self.ircClient.send_private_message_to_IRC("!i won")
            if (line[0] == "ILOST"):
                self.ircClient.send_private_message_to_IRC("!i lost")
            if (line[0] == "CLEAROVERLAY"):
                GameData.clear_overlay_HTML()
            if (
                len(line) >= 4
                and "PRIVMSG" == line[2]
                and "jtv" not in line[0]
            ):
                # call function to handle user message
                self.user_message(line)

    def user_message(self, line):
        """Processes IRC returned raw string data."""

        # Dissect out the useful parts of the raw data line
        # into username and message and remove certain characters
        msgFirst = line[1]
        msgUserName = msgFirst[1:]
        msgUserName = msgUserName.split("!")[0]
        # msgType = line [1];
        # msgChannel = line [3]
        msgMessage = " ".join(line[4:])
        msgMessage = msgMessage[1:]
        messageString = str(msgUserName) + " : " + str(msgMessage)
        logging.info(str(messageString).encode('utf8'))

        # Check for UserCommands
        self.check_for_user_command(msgUserName, msgMessage)

        if (
            msgMessage == "exit"
            and msgUserName == self.ircClient.adminUserName
        ):
            self.ircClient.send_private_message_to_IRC("Exiting")
            self.close()

    def check_for_user_command(self, userName, message):
        """Performs string comparisons for hardcoded commands."""

        logging.info("Checking For User Comamnd")
        try:
            if (
                bool(re.match(r"^(!)?opponent(\?)?$", message.lower()))
                or bool(re.match(r"^(!)?place your bets$", message.lower()))
                or bool(re.match(r"^(!)?opp(\?)?$", message.lower()))
                    ):

                self.gameData = GameData(
                    ircClient=self.ircClient,
                    settings=self.settings
                )
                if self.gameData.get_data_from_game():
                    self.gameData.output_opponent_data()
                else:
                    self.ircClient.send_private_message_to_IRC(
                        "Can't find the opponent right now."
                    )

            user = str(userName).lower()
            admin = str(self.settings.privatedata.get('adminUserName'))
            channel = str(self.settings.data.get('channel'))
            if (
                message.lower() == "test"
                and (
                    user == admin.lower()
                    or user == channel.lower())
                    ):
                self.ircClient.send_private_message_to_IRC(
                    "I'm here! Pls give me mod to prevent twitch"
                    " from autobanning me for spam if I have to send"
                    " a few messages quickly."
                )
                self.ircClient.output.insert(
                    END,
                    f"Oh hi again, I heard you in the {self.channel[1:]}"
                    " channel.\n"
                )

            if (bool(re.match(r"^(!)?gameinfo(\?)?$", message.lower()))):
                self.game_info()

            if (bool(re.match(r"^(!)?story(\?)?$", message.lower()))):
                self.story()

            if (bool(re.match(r"^(!)?debug(\?)?$", message.lower()))):
                self.print_info_to_debug()

        except Exception as e:
            logging.error("Problem in CheckForUserCommand")
            logging.error(str(e))
            logging.exception("Exception : ")

    def print_info_to_debug(self):
        """Outputs gameData to the log file."""

        try:
            self.gameData = GameData(
                self.ircClient,
                settings=self.settings
            )
            self.gameData.get_data_from_game()
            self.gameData.get_mapDescriptionFull_from_UCS_file()
            self.gameData.get_mapNameFull_from_UCS_file()
            logging.info(self.gameData)
            self.ircClient.send_private_message_to_IRC(
                "GameData saved to log file."
            )
        except Exception as e:
            logging.error("Problem in PrintInfoToDebug")
            logging.error(str(e))
            logging.exception("Exception : ")

    def game_info(self):
        """Outputs a summary of the current game to IRC."""

        self.gameData = GameData(self.ircClient, settings=self.settings)
        if self.gameData.get_data_from_game():
            self.ircClient.send_private_message_to_IRC(
                f"Map : {self.gameData.mapNameFull},"
                f" High Resources : {self.gameData.highResources},"
                f" Automatch : {self.gameData.automatch},"
                f" Slots : {self.gameData.slots},"
                f" Players : {self.gameData.numberOfPlayers}."
            )

    def story(self):
        """Outputs the game description to IRC."""

        self.gameData = GameData(self.ircClient, settings=self.settings)
        logging.info(str(self.gameData))
        if self.gameData.get_data_from_game():
            logging.info(str(self.gameData))
            # Requires parsing the map description from
            # the UCS file this takes time so must be done first
            self.gameData.get_mapDescriptionFull_from_UCS_file()
            self.ircClient.send_private_message_to_IRC(
                "{}.".format(self.gameData.mapDescriptionFull))

    def test_output(self):
        """Outputs information general on pressing test button."""

        if not self.gameData:
            self.gameData = GameData(
                self.ircClient,
                settings=self.settings
            )
            self.gameData.get_data_from_game()
        self.gameData.test_output()

    def close(self):
        """Closes the IRC channel."""

        self.running = False
        logging.info("Closing Channel " + str(self.channel) + " thread.")