190 lines
7.7 KiB
Python
Executable File
190 lines
7.7 KiB
Python
Executable File
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
|
|
class TimerExpiredError(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 isinstance(error, TimerExpiredError):
|
|
embed.colour = discord.Colour.red()
|
|
embed.add_field(name="Timer", value=f"The timer expired!", inline=False)
|
|
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)
|
|
|
|
message = None
|
|
|
|
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 asyncio.TimeoutError:
|
|
if message != None:
|
|
await message.edit(embed=create_embed(ctx.author, arg, timer, TimerExpiredError()))
|
|
|
|
|
|
# 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))
|