예제 #1
0
    async def on_ready(self):
        await self.bot.wait_until_ready()
        self.CommandRconSettings = self.bot.cogs["CommandRconSettings"]
        self.RateBucket = RateBucket(self.streamMsg)

        self.CommandArma = self.bot.cogs["CommandArma"]
        self.readLog = self.CommandArma.readLog

        if ("streamChat" in self.rcon_settings
                and self.rcon_settings["streamChat"] != None):
            self.streamChat = self.bot.get_channel(
                self.rcon_settings["streamChat"])
            #self.streamChat.send("TEST")
        else:
            self.streamChat = None

        self.setupRcon()
예제 #2
0
class CommandRcon(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        self.path = os.path.dirname(os.path.realpath(__file__))

        self.arma_chat_channels = [
            "Side", "Global", "Vehicle", "Direct", "Group", "Command"
        ]

        #Load cfg:
        self.rcon_settings = CoreConfig.cfg.new(
            self.path + "/" + utils.Modules.settings_dir + "rcon.json",
            self.path + "/" + utils.Modules.settings_dir + "rcon.default_json")
        CoreConfig.modules["modules/rcon"]["rcon"] = self.rcon_settings
        CoreConfig.registered.append(self.rcon_settings)

        self.lastReconnect = deque()
        self.ipReader = geoip2.database.Reader(self.path +
                                               "/GeoLite2-Country.mmdb")
        self.arma_rcon = None

        asyncio.ensure_future(self.on_ready())

    async def on_ready(self):
        await self.bot.wait_until_ready()
        self.CommandRconSettings = self.bot.cogs["CommandRconSettings"]
        self.RateBucket = RateBucket(self.streamMsg)

        try:
            self.CommandArma = self.bot.cogs["CommandArma"]
            self.readLog = self.CommandArma.readLog
        except KeyError:
            self.readLog = None
            self.CommandArma = None

        if ("streamChat" in self.rcon_settings
                and self.rcon_settings["streamChat"] != None):
            self.streamChat = self.bot.get_channel(
                self.rcon_settings["streamChat"])
            #self.streamChat.send("TEST")
        else:
            self.streamChat = None

        self.setupRcon()

    def setupRcon(self, serverMessage=None):
        try:
            Events = None
            if self.arma_rcon:
                Events = self.arma_rcon.Events.copy()
            del self.arma_rcon
            self.arma_rcon = bec_rcon.ARC(
                self.rcon_settings["ip"], self.rcon_settings["password"],
                self.rcon_settings["port"],
                {'timeoutSec': self.rcon_settings["timeoutSec"]})
            if Events:
                #restore Event Handlers
                self.arma_rcon.Events = Events
            else:
                #Add Event Handlers
                self.arma_rcon.add_Event("received_ServerMessage",
                                         self.rcon_on_msg_received)
                self.arma_rcon.add_Event("on_disconnect",
                                         self.rcon_on_disconnect)

            if (serverMessage):
                self.arma_rcon.serverMessage = serverMessage
            else:
                #Extend the chat storage
                data = self.arma_rcon.serverMessage.copy()
                self.arma_rcon.serverMessage = deque(maxlen=500)  #Default: 100
                data.reverse()
                for d in data:
                    self.arma_rcon.serverMessage.append(d)
        except Exception as e:
            log.print_exc()
            log.error(e)

###################################################################################################
#####                                  common functions                                        ####
###################################################################################################

#converts unicode to ascii, until utf-8 is supported by rcon

    def setEncoding(self, msg):
        return bytes(msg.encode()).decode("utf-8", "replace")

    def getPlayerFromMessage(self, message: str):
        if (":" in message):
            header, body = message.split(":", 1)
            if (self.isChannel(header)):  #was written in a channel
                player_name = header.split(") ")[1]
                return player_name
        return False

    def isChannel(self, msg):
        for channel in self.arma_chat_channels:
            if (channel in msg):
                return True
        return False

    #check if there was chat activity by the player in the last [min] minutes
    def playerTypesMessage(self, player_name, min=25):
        data = self.arma_rcon.serverMessage.copy()
        data.reverse()
        for pair in data:  #checks all recent chat messages
            msg = pair[1]
            diff = datetime.datetime.now() - pair[0]
            #cancel search if chat is older than 25min
            if (diff.total_seconds() > 0 and diff.total_seconds() / 60 >= min):
                break
            msg_player = self.getPlayerFromMessage(msg)
            if (msg_player != False and player_name == msg_player
                    or (" " + player_name + " disconnected") in msg
                    or (player_name in msg and " has been kicked by BattlEye"
                        in msg)):  #if player wrote something return True
                return True
        return False

    async def streamMsg(self, message_list):
        msg = "\n".join(message_list)
        if (len(msg.strip()) > 0):
            await self.streamChat.send(msg)

###################################################################################################
#####                                BEC Rcon Event handler                                    ####
###################################################################################################
#function called when a new message is received by rcon

    def rcon_on_msg_received(self, args):
        message = discord.utils.escape_markdown(args[0], as_needed=True)

        if ("CommandRconIngameComs" in self.bot.cogs):
            asyncio.ensure_future(self.bot.cogs["CommandRconIngameComs"].
                                  RconCommandEngine.parseCommand(args[0]))
        #example: getting player name
        if (":" in message):
            header, body = message.split(":", 1)
            if (self.isChannel(header)):  #was written in a channel
                #check for admin notification keywords
                asyncio.ensure_future(
                    self.CommandRconSettings.checkKeyWords(body))
                player_name = header.split(") ")[1]
                #log.info(player_name)
                #log.info(body)
                #else: is join or disconnect, or similar

                #check if the chat is streamed or not
                if (self.streamChat != None):
                    self.RateBucket.add(message)

    #event supports async functions
    #function is called when rcon disconnects
    async def rcon_on_disconnect(self):
        await asyncio.sleep(10)

        # cleanup old records
        try:
            while self.lastReconnect[0] < datetime.datetime.now(
            ) - datetime.timedelta(seconds=60):
                self.lastReconnect.popleft()
        except IndexError:
            pass  # there are no records in the queue.
        if len(self.lastReconnect
               ) > self.rcon_settings["max_reconnects_per_minute"]:
            log.warning("Stopped Reconnecting - Too many reconnects!")
            if (self.streamChat):
                await self.streamChat.send(
                    ":warning: Stopped Reconnecting - Too many reconnects!\n Reconnect with '!reconnect'"
                )
        else:
            self.lastReconnect.append(datetime.datetime.now())
            log.info("Reconnecting to BEC Rcon")
            self.setupRcon(
                self.arma_rcon.serverMessage
            )  #restarts form scratch (due to weird behaviour on reconnect)

    def generateChat(self, limit):
        msg = ""
        data = self.arma_rcon.serverMessage.copy()
        start = len(data) - 1
        if (start > limit):
            end = start - limit
        else:
            end = 0
        i = end
        while (i <= start):
            pair = data[i]
            time = pair[0]
            msg += time.strftime("%H:%M:%S") + " | " + pair[1] + "\n"
            i += 1
        return discord.utils.escape_markdown(msg, as_needed=True)

###################################################################################################
#####                                BEC Rcon custom commands                                  ####
###################################################################################################

    @CommandChecker.command(name='reconnect',
                            brief="Reconnects to the Rcon Server",
                            aliases=['reconnectrcon'],
                            pass_context=True)
    async def reconnectrcon(self, ctx):
        if (self.arma_rcon.disconnected == True):
            self.setupRcon(self.arma_rcon.serverMessage)
            await ctx.send("Reconnected Rcon")
        else:
            await ctx.send(
                "Disconnecting and waiting for 45s before reconnecting...")
            await asyncio.sleep(46)
            self.setupRcon(self.arma_rcon.serverMessage)
            await ctx.send("Reconnected.")

    @CommandChecker.command(name='disconnect',
                            brief="Terminates the connection to Rcon",
                            aliases=['disconnectrcon'],
                            pass_context=True)
    async def disconnectrcon(self, ctx):
        self.lastReconnect.append(datetime.datetime.now())
        self.arma_rcon.disconnect()
        await ctx.send("Disconnect Rcon")

    @CommandChecker.command(
        name='streamChat',
        brief="Streams the arma 3 chat live into the current channel",
        aliases=['streamchat'],
        pass_context=True)
    async def stream(self, ctx):
        self.streamChat = ctx
        self.rcon_settings["streamChat"] = ctx.message.channel.id

        await ctx.send("Streaming chat...")

    @CommandChecker.command(name='stopStream',
                            brief="Stops the stream",
                            aliases=['stopstream'],
                            pass_context=True)
    async def streamStop(self, ctx):
        self.streamChat = None
        self.rcon_settings["streamChat"] = None
        await ctx.send("Stream stopped")

    @CommandChecker.command(name='checkAFK',
                            brief="Checks if a player is AFK (5min)",
                            aliases=['checkafk'],
                            pass_context=True)
    async def checkAFK(self, ctx, player_id: int):
        players = await self.arma_rcon.getPlayersArray()
        player_name = None
        for player in players:
            if (int(player[0]) == player_id):
                player_name = player[4]
        if (player_name.endswith(" (Lobby)")):  #Strip lobby from name
            player_name = player_name[:-8]
        if (player_name == None):
            await ctx.send("Player not found")
            return
        msg = "Starting AFK check for: ``" + str(player_name) + "``"
        await ctx.send(msg)
        already_active = False
        for i in range(0, 300):  #checks for 5min (10*30s)
            if (self.playerTypesMessage(player_name)):
                if (i == 0):
                    already_active = True
                    await ctx.send(
                        "Player was recently active. Canceling AFK check.")
                else:
                    await ctx.send(
                        "Player responded in chat. Canceling AFK check.")
                if (already_active == False):
                    await self.arma_rcon.sayPlayer(
                        player_id, "Thank you for responding in chat.")
                return
            if ((i % 30) == 0):
                try:
                    for k in range(0, 3):
                        await self.arma_rcon.sayPlayer(
                            player_id,
                            "Type something in chat or you will be kicked for being AFK. ("
                            + str(round(i / 30) + 1) + "/10)")
                except:
                    log.error("Failed to send command sayPlayer (checkAFK)")
            await asyncio.sleep(1)
        if (self.playerTypesMessage(player_name)):
            if (i == 0):
                already_active = True
            await ctx.send("Player responded in chat. Canceling AFK check.")
            if (already_active == False):
                try:
                    await self.arma_rcon.sayPlayer(
                        player_id, "Thank you for responding in chat.")
                except:
                    log.error("Failed to send command sayPlayer")
            return
        else:
            await self.arma_rcon.kickPlayer(player_id, "AFK too long")
            await ctx.send("``" + str(player_name) +
                           "`` did not respond and was kicked for being AFK")

    @CommandChecker.command(name='status',
                            brief="Current connection status",
                            pass_context=True)
    async def status(self, ctx, limit=20):
        msg = ""
        if (self.arma_rcon.disconnected == False):
            msg += "Connected to: " + self.arma_rcon.serverIP + "\n"
        else:
            msg += "Currently not connected: " + self.arma_rcon.serverIP + "\n"
        msg += str(len(self.arma_rcon.serverMessage)) + " Messages collected"
        await ctx.send(msg)

    @CommandChecker.command(name='getChat',
                            brief="Get the last ingame chat messages",
                            aliases=['getchat'],
                            pass_context=True)
    async def getChat(self, ctx, limit=20):
        msg = self.generateChat(limit)
        await utils.sendLong(ctx, msg)

    @CommandChecker.command(name='players+',
                            brief="Lists current players on the server",
                            pass_context=True)
    async def playersPlus(self, ctx):
        players = await self.arma_rcon.getPlayersArray()

        limit = 100
        i = 1
        new = False
        msg = "Players: \n"
        for player in players:
            if (i <= limit):
                id, ip, ping, guid, name = player

                if (self.playerTypesMessage(name)):
                    active = ":green_circle:"
                else:
                    active = ":white_circle:"
                #fetch country
                try:
                    response = self.ipReader.country(ip.split(":")[0])
                    region = str(response.country.iso_code).lower()
                except:
                    region = ":question:"

                if (region == "none"):
                    flag = ":question:"  #symbol if no country was found
                else:
                    flag = ":flag_{}:".format(region)
                msg += "{}#{} | {} {}".format(
                    active, id, flag,
                    discord.utils.escape_markdown(name, as_needed=True)) + "\n"

        await utils.sendLong(ctx, msg)


###################################################################################################
#####                                   BEC Rcon commands                                      ####
###################################################################################################

    @CommandChecker.command(
        name='command',
        brief="Sends a custom command to the server",
        help=
        "Executes any command by directly sending the input to the server. Will return if the command was executed. For example '!command say -1 hello' will send a global message",
        pass_context=True)
    async def command(self, ctx, *message):
        message = " ".join(message)
        message = self.setEncoding(message)
        data = await self.arma_rcon.command(message)
        if (len(data) == 0):
            msg = "Executed command: ``" + str(
                message) + "`` and returned nothing (confirmed its execution)"
        else:
            msg = "Executed command: ``" + str(
                message) + "`` wich returned: " + str(data)
        await utils.sendLong(ctx, msg)

    @CommandChecker.command(
        name='kickPlayer',
        brief="Kicks a player who is currently on the server",
        aliases=['kickplayer'],
        pass_context=True)
    async def kickPlayer(self, ctx, player_id: int, *message):
        message = " ".join(message)
        message = self.setEncoding(message)
        await self.arma_rcon.kickPlayer(player_id, message)

        msg = "kicked player: " + str(player_id)
        await ctx.send(msg)

    @CommandChecker.command(name='say',
                            brief="Sends a global message",
                            pass_context=True)
    async def sayGlobal(self, ctx, *message):
        name = ctx.message.author.name
        message = " ".join(message)
        message = self.setEncoding(message)
        await self.arma_rcon.sayGlobal(name + ": " + message)
        msg = "Send: ``" + message + "``"
        await ctx.send(msg)

    @CommandChecker.command(name='sayPlayer',
                            brief="Sends a message to a specific player",
                            aliases=['sayplayer', 'sayp'],
                            pass_context=True)
    async def sayPlayer(self, ctx, player_id: int, *message):
        message = " ".join(message)
        message = self.setEncoding(message)
        name = ctx.message.author.name
        if (len(message) < 2):
            message = "Ping"
        await self.arma_rcon.sayPlayer(player_id, name + ": " + message)
        msg = "Send msg: ``" + str(player_id) + "``" + message
        await ctx.send(msg)

    @CommandChecker.command(
        name='loadScripts',
        brief=
        "Loads the 'scripts.txt' file without the need to restart the server",
        aliases=['loadscripts'],
        pass_context=True)
    async def loadScripts(self, ctx):
        await self.arma_rcon.loadScripts()
        msg = "Loaded Scripts!"
        await ctx.send(msg)

    @CommandChecker.command(name='loadEvents',
                            aliases=['loadevents'],
                            brief="Loads Events",
                            pass_context=True)
    async def loadEvents(self, ctx):
        await self.arma_rcon.loadEvents()
        msg = "Loaded Events!"
        await ctx.send(msg)

    @CommandChecker.command(
        name='maxPing',
        brief=
        "Changes the MaxPing value. If a player has a higher ping, he will be kicked from the server",
        aliases=['maxping'],
        pass_context=True)
    async def maxPing(self, ctx, ping: int):
        await self.arma_rcon.maxPing(ping)
        msg = "Set maxPing to: " + ping
        await ctx.send(msg)

    @CommandChecker.command(name='changePassword',
                            brief="Changes the RCon password",
                            aliases=['changepassword'],
                            pass_context=True)
    async def changePassword(self, ctx, *password):
        password = "******".join(password)
        await self.arma_rcon.changePassword(password)
        msg = "Set Password to: ``" + password + "``"
        await ctx.send(msg)

    @CommandChecker.command(name='loadBans',
                            brief="(Re)load the BE ban list from bans.txt",
                            aliases=['loadbans'],
                            pass_context=True)
    async def loadBans(self, ctx):
        await self.arma_rcon.loadBans()
        msg = "Loaded Bans!"
        await ctx.send(msg)

    @CommandChecker.command(name='players',
                            brief="Lists current players on the server",
                            pass_context=True)
    async def players(self, ctx):
        players = await self.arma_rcon.getPlayersArray()
        msgtable = prettytable.PrettyTable()
        msgtable.field_names = ["ID", "Name", "IP", "GUID"]
        msgtable.align["ID"] = "r"
        msgtable.align["Name"] = "l"
        msgtable.align["IP"] = "l"
        msgtable.align["GUID"] = "l"

        limit = 100
        i = 1
        new = False
        msg = ""
        for player in players:
            if (i <= limit):
                msgtable.add_row([
                    player[0],
                    discord.utils.escape_markdown(player[4], as_needed=True),
                    player[1], player[3]
                ])
                if (len(str(msgtable)) < 1800):
                    i += 1
                    new = False
                else:
                    msg += "```"
                    msg += str(msgtable)
                    msg += "```"
                    await ctx.send(msg)
                    msgtable.clear_rows()
                    msg = ""
                    new = True
        if (new == False):
            msg += "```"
            msg += str(msgtable)
            msg += "```"
            await ctx.send(msg)

    @CommandChecker.command(name='admins',
                            brief="Lists current admins on the server",
                            pass_context=True)
    async def admins(self, ctx):
        admins = await self.arma_rcon.getAdminsArray()
        msgtable = prettytable.PrettyTable()
        msgtable.field_names = ["ID", "IP"]
        msgtable.align["ID"] = "r"
        msgtable.align["IP"] = "l"

        limit = 100
        i = 1
        new = False
        msg = ""
        for admin in admins:
            if (i <= limit):
                msgtable.add_row([admin[0], admin[1]])
                if (len(str(msgtable)) < 1800):
                    i += 1
                    new = False
                else:
                    msg += "```"
                    msg += str(msgtable)
                    msg += "```"
                    await ctx.send(msg)
                    msgtable.clear_rows()
                    msg = ""
                    new = True
        if (new == False):
            msg += "```"
            msg += str(msgtable)
            msg += "```"
            await ctx.send(msg)

    @CommandChecker.command(name='getMissions',
                            brief="Gets a list of all Missions",
                            aliases=['getmissions'],
                            pass_context=True)
    async def getMissions(self, ctx):
        missions = await self.arma_rcon.getMissions()
        await utils.sendLong(ctx, missions)

    @CommandChecker.command(name='loadMission',
                            brief="Loads a mission",
                            aliases=['loadmission'],
                            pass_context=True)
    async def loadMission(self, ctx, mission: str):
        if (mission.endswith(".pbo", -4)):  #Strips PBO
            mission = mission[:-4]
        await self.arma_rcon.loadMission(mission)
        msg = "Loaded mission: ``" + str(missions) + "``"
        await ctx.send(msg)

    @CommandChecker.command(
        name='banPlayer',
        brief="Ban a player with his player id from the server.",
        help=
        "Kicks and Bans a player with the specifed BE player id (usually 0-100)",
        aliases=['banplayer'],
        pass_context=True)
    async def banPlayer(self, ctx, player_id, time=0, *message):
        message = " ".join(message)
        message = self.setEncoding(message)
        if (len(message) < 2):
            await self.arma_rcon.banPlayer(player=player, time=time)
        else:
            await self.arma_rcon.banPlayer(player, message, time)

        msg = "Banned player: ``" + str(
            player) + " - " + matches[0] + "`` with reason: " + message
        await ctx.send(msg)

    @CommandChecker.command(
        name='addBan',
        brief="Ban a player with GUID (even if they are offline)",
        aliases=['addban'],
        help="Adds a ban to the ban (GUID) list",
        pass_context=True)
    async def addBan(self, ctx, GUID: str, time=0, *message):
        message = " ".join(message)
        message = self.setEncoding(message)
        matches = ["?"]
        if (len(GUID) != 32):
            raise Exception("Invalid GUID")
        if (len(message) < 2):
            await self.arma_rcon.addBan(guid=GUID, time=time)
        else:
            await self.arma_rcon.addBan(GUID, message, time)

        msg = "Banned player: ``" + str(
            GUID) + " - " + matches[0] + "`` with reason: " + message

    @CommandChecker.command(name='removeBan',
                            brief="Removes a ban",
                            aliases=['removeban'],
                            pass_context=True)
    async def removeBan(self, ctx, banID: int):
        await self.arma_rcon.removeBan(banID)

        msg = "Removed ban: ``" + str(banID) + "``"
        await ctx.send(msg)

    @CommandChecker.command(name='getBans',
                            brief="Removes a ban",
                            aliases=['getbans'],
                            pass_context=True)
    async def getBans(self, ctx):
        bans = await self.arma_rcon.getBansArray()
        bans.reverse()  #news bans first
        msgtable = prettytable.PrettyTable()
        msgtable.field_names = ["ID", "GUID", "Time", "Reason"]
        msgtable.align["ID"] = "r"
        msgtable.align["IP"] = "l"
        msgtable.align["GUID"] = "l"

        limit = 20
        i = 1
        new = False
        msg = ""
        for ban in bans:
            if (i <= limit):
                if (len(str(msgtable)) < 1700):
                    msgtable.add_row([ban[0], ban[1], ban[2], ban[3]])
                    i += 1
                    new = False
                else:
                    msg += "```"
                    msg += str(msgtable)
                    msg += "```"
                    await ctx.send(msg)
                    msgtable.clear_rows()
                    msg = ""
                    new = True
        if (new == False):
            msg += "```"
            msg += str(msgtable)
            msg += "```"
            await ctx.send(msg)
        if (i >= limit):
            msg = "Limit of " + str(
                limit) + " reached. There are still " + str(len(bans) -
                                                            i) + " more bans"
            await ctx.send(msg)

    @CommandChecker.command(name='getBEServerVersion',
                            brief="Gets the current version of the BE server",
                            aliases=['beversion', 'BEversion', 'BEVersion'],
                            pass_context=True)
    async def getBEServerVersion(self, ctx):
        version = await self.arma_rcon.getBEServerVersion()
        msg = "BE version: ``" + str(version) + "``"
        await ctx.send(msg)

    @CommandChecker.command(
        name='lock',
        brief="Locks the server. No one will be able to join",
        pass_context=True)
    async def lock(self, ctx):
        data = await self.arma_rcon.lock()
        msg = "Locked the Server"
        await ctx.send(msg)

    @CommandChecker.command(name='unlock',
                            brief="Unlocks the Server",
                            pass_context=True)
    async def unlock(self, ctx):
        data = await self.arma_rcon.unlock()
        msg = "Unlocked the Server"
        await ctx.send(msg)

    @CommandChecker.command(name='shutdown',
                            brief="Shutdowns the Server",
                            pass_context=True)
    async def shutdown(self, ctx):
        data = await self.arma_rcon.shutdown()
        msg = "Shutdown the Server"
        await ctx.send(msg)

    @CommandChecker.command(
        name='restart',
        brief="Restart mission with current player slot selection",
        pass_context=True)
    async def restart(self, ctx):
        data = await self.arma_rcon.restart()
        msg = "Restarting the Mission"
        await ctx.send(msg)

    @CommandChecker.command(
        name='restartServer',
        brief="Shuts down and restarts the server immediately",
        pass_context=True)
    async def restartServer(self, ctx):
        data = await self.arma_rcon.restartServer()
        msg = "Restarting the Server"
        await ctx.send(msg)

    @CommandChecker.command(
        name='restartM',
        brief="Shuts down and restarts the server after mission ends",
        pass_context=True)
    async def restartserveraftermission(self, ctx):
        data = await self.arma_rcon.restartserveraftermission()
        msg = "Restarting the Server after mission ends"
        await ctx.send(msg)

    @CommandChecker.command(name='shutdownM',
                            brief="Shuts down the server after mission ends",
                            pass_context=True)
    async def shutdownserveraftermission(self, ctx):
        data = await self.arma_rcon.shutdownserveraftermission()
        msg = "Shuting down the Server after mission ends"
        await ctx.send(msg)

    @CommandChecker.command(
        name='reassign',
        brief="Sends all players back to the lobby and unslots them",
        pass_context=True)
    async def reassign(self, ctx):
        data = await self.arma_rcon.reassign()
        msg = "All users are send back to the lobby"
        await ctx.send(msg)

    @CommandChecker.command(
        name='monitords',
        brief=
        "Shows performance information in the dedicated server console. Tracks the performance for 10s",
        pass_context=True)
    async def monitords(
        self,
        ctx,
    ):
        if (not self.readLog):
            raise Exception("Arma module required, but not loaded!")

        async def sendLoad(event, timestamp, msg, event_match):
            await ctx.send(msg)

        self.readLog.EH.add_Event("Server load", sendLoad)
        await self.arma_rcon.monitords(1)
        await asyncio.sleep(5)
        await self.arma_rcon.monitords(0)
        self.readLog.EH.remove_Event("Server load", sendLoad)

    @CommandChecker.command(name='goVote',
                            brief="Users can vote for the mission selection.",
                            aliases=['govote'],
                            pass_context=True)
    async def goVote(self, ctx):
        data = await self.arma_rcon.goVote()
        msg = "Sending users to vote for next mission"
        await ctx.send(msg)