import discord from discord.ext import commands import random import string import socket import asyncio import threading from functions.timer import Timer from data import constants from functions.emoji_check import * import re from data.DatabaseConnection import * # 25216 --> uuid server # 25224 --> send chat server def get_random_string(length): # Random string with the combination of lower and upper case letters = string.ascii_letters + "0123456789" result_str = ''.join(random.choice(letters) for i in range(length)) return result_str class PlayerError(Exception): pass class WrongCodeError(Exception): pass def get_player_uuid(minecraftname): HOST = '192.168.1.214' # The server's hostname or IP address PORT = 25216 # The port used by the server with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((HOST, PORT)) s.send(bytes("{}\n".format(minecraftname), encoding="ascii")) data = s.recv(1024) data_string = data.decode("utf-8").strip('\n') if data_string == "PlayerError": raise PlayerError() return data_string def send_chat(discordname, minecraftname, code): HOST = '192.168.1.214' # The server's hostname or IP address PORT = 25224 # The port used by the server with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((HOST, PORT)) s.send(bytes("{}\t{}\t{}\n".format(deEmojify(discordname), minecraftname, code), encoding="ascii")) data = s.recv(1024) data_string = data.decode("utf-8").strip('\n') if data_string == "PlayerError": raise PlayerError() return data_string class PlayerLink(commands.Cog): def __init__(self, client): self.client = client def get_linked_role(self): return discord.utils.get(self.client.get_guild(constants.WorldCraft).roles, id=constants.roleLinked) @commands.command(name="Link") async def link(self, ctx, arg): channelid = ctx.channel.id authorid = ctx.author.id if channelid == constants.DiscordLinkerID: dbLinker = PlayerDBLinker() if dbLinker.discordidused(authorid): await ctx.send(f"{ctx.author.mention}, your account is already linked!") dbLinker.close() return code = get_random_string(8) def check(message: discord.Message): return message.channel.id == channelid and message.author.id == authorid # creates the embed for the link message def create_embed(discord_author, minecraftname, timer, error=None, success=False): embed = discord.Embed(title="WorldCraft Linker") embed.add_field(name="How to:", value= "A code has been sent to your minecraft chat in the WorldCraft server.\nSend the code in this channel.") embed.add_field(name="Minecraft Name:", value=f"{minecraftname}", inline=False) embed.add_field(name="Discord Name:", value=f"{discord_author.mention}", inline=False) # use dictionary and set color string before the message: example => r(ed):message if isinstance(error, WrongCodeError): embed.add_field(name="Error", value=f"The code is wrong!", inline=False) embed.colour = discord.Colour.red() elif (success == True): embed.add_field(name="Success", value=f"The link was successfull!", inline=False) embed.colour = discord.Colour.green() elif (timer.ended): embed.add_field(name="Timer", value=f"The code is expired!", inline=False) embed.colour = discord.Colour.red() elif (timer.minutes == 2): embed.add_field(name="Timer", value=f"The code will expire in { str(timer.minutes)} minutes", inline=False) embed.colour = discord.Colour.orange() elif (timer.minutes < 2): embed.add_field(name="Timer", value=f"The code will expire in less than { str(timer.minutes + 1)} {'minutes' if timer.minutes + 1 > 1 else 'minute'}", inline=False) embed.colour = discord.Colour.orange() else: embed.add_field(name="Timer", value=f"The code will expire in {str(timer.minutes).zfill(2)}:{str(timer.seconds).zfill(2)}", inline=False) embed.colour = discord.Colour.orange() return embed async def send_timer_messages(timer, message): while (not timer.ended): # maybe create a task from this because this takes some time -> timer not accurate if ((timer.minutes < 2 and timer.seconds == 59) or (timer.minutes == 0 and timer.seconds == 0)): asyncio.create_task(message.edit(embed=create_embed(ctx.author, arg, timer))) await asyncio.sleep(1) try: uuid = get_player_uuid(arg) send_chat(ctx.author.name, arg, code) #message_send_time = timer = Timer(2, 0) timer.start() message = await ctx.send(embed=create_embed(ctx.author, arg, timer)) task = asyncio.create_task(send_timer_messages(timer, message)) # Wait for the code response msg = await self.client.wait_for('message', check=check, timeout=120) if msg.content == code: dbLinker = PlayerDBLinker() try: dbLinker.linkPlayer(uuid, authorid) await ctx.author.add_roles(self.get_linked_role()) timer.stop() await message.edit(embed=create_embed(ctx.author, arg, timer, success=True)) except SQLInsertError: await message.edit(embed=create_embed(ctx.author, arg, timer)) finally: dbLinker.close() else: # this stops the timer task timer.stop() await message.edit(embed=create_embed(ctx.author, arg, timer, WrongCodeError())) except PlayerError: await ctx.send("Player '" + arg + "' not found") # except: # await ctx.send("Something went wrong") @commands.command(name="Unlink") async def unlink(self, ctx): authorid = ctx.author.id channelid = ctx.channel.id if channelid == constants.DiscordLinkerID: dbLinker = PlayerDBLinker() try: dbLinker.unlinkPlayer(authorid) await ctx.author.remove_roles(self.get_linked_role()) await ctx.send(f"{ctx.author.mention}, unlinked your account") except UnLinkError: await ctx.send("The unlink was unsuccessfull") except WrongMinecraftName: await ctx.send("Wrong minecraft name!") except PlayerNotLinked: await ctx.send("Player not linked!") finally: dbLinker.close() def setup(client): client.add_cog(PlayerLink(client))