import socket import discord import asyncio import configparser from datetime import timedelta config = configparser.ConfigParser() config.read('settings.ini') SERV_IP = config["bot"]["ServerIP"] SERV_PORT = config["bot"].getint("ServerPort") LOCAL_IP = "127.0.0.1" SERV = (SERV_IP, SERV_PORT) RCON_PASS = config["bot"]["RconPassword"] DISCORD_TOKEN = config["bot"]["DiscordToken"] if not RCON_PASS or not DISCORD_TOKEN: raise Exception("please make sure to set the discord token and rcon password in settings.ini") def udp(msg): sock = socket.socket(socket.AF_INET, # Internet socket.SOCK_DGRAM) # UDP sock.sendto(bytes([255,255,255,255]) + str.encode(msg), SERV) sock.settimeout(5) return str(sock.recv(1024 * 16)[4:], "ascii") def rcon(command): return udp("rcon " + RCON_PASS + " " + command) def parse_statusResponse(data): raw_list = data.split('\\')[1:] result = {} for i in range(0,len(raw_list),2): result[raw_list[i]] = raw_list[i+1] return result def parse_users(data): res = [] for d in data: if not d: continue user = {} splitData = d.split(' ') user["score"] = splitData[0] user["ping"] = splitData[1] user["nick"] = " ".join(splitData[2:])[1:-1] res.append(user) return res def get_status(): status = udp("getstatus") data = status.split('\n')[1:] return parse_statusResponse(data[0]), parse_users(data[1:]) def max_clients(): return int(get_status()['sv_maxclients']) class MyClient(discord.Client): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.bg_task = self.loop.create_task(self.check_players()) async def handler_print(data, message): if not data: return await message.channel.send("```\n" + data + "```\n") handlers = { "print" : handler_print } async def check_players(self): await self.wait_until_ready() while not self.is_closed(): try: status, players = get_status() act = discord.Activity(name="%d/%s Players" % (len(players), status['sv_maxclients'])) act.type = discord.ActivityType.watching act.state = status['mapname'] act.details = status['sv_hostname'] except: act = discord.Game("Server not responding") await self.change_presence(activity=act) await asyncio.sleep(5) async def on_ready(self): print('Logged on as', self.user) async def on_message(self, message): # don't respond to ourselves if message.author == self.user or message.author.bot: return if "!getstatus" in message.content.lower(): try: status, players = get_status() if not players: await message.channel.send("No players on the server") return embed = discord.Embed(title = status["sv_hostname"]) pings = '\n'.join([p["ping"] for p in players]) nicks = '\n'.join([p["nick"] for p in players]) scores = '\n'.join([p["score"] for p in players]) embed.add_field(name = "Ping", value = pings) embed.add_field(name = "Score", value = scores) embed.add_field(name = "Nick", value = nicks) await message.channel.send(" ", embed=embed) except: await message.channel.send("Unable to reach server") return if message.content[0] == '!': try: status = rcon(message.content[1:]) if "rcon" in message.content.lower(): return statusType = status.split('\n')[0] data = '\n'.join(status.split('\n')[1:]) await self.handlers[statusType](data, message) except: await message.channel.send("Unable to reach server") else: try: rcon("say [%s]: %s" % (message.author.display_name, message.content)) except: await message.channel.send("Unable to reach server") client = MyClient() client.run(DISCORD_TOKEN)