From 42b911342bdb832c056cc64a068aa21f0c213a27 Mon Sep 17 00:00:00 2001 From: skelmis Date: Thu, 27 Aug 2020 23:37:49 +1200 Subject: [PATCH] Add examples usages. --- examples/Parsers.py | 75 -------------- examples/Player.py | 232 -------------------------------------------- 2 files changed, 307 deletions(-) delete mode 100644 examples/Parsers.py delete mode 100644 examples/Player.py diff --git a/examples/Parsers.py b/examples/Parsers.py deleted file mode 100644 index 99c7571..0000000 --- a/examples/Parsers.py +++ /dev/null @@ -1,75 +0,0 @@ -import re -import json - -""" -A file for Player utilities, focused around parsing chat and making it human readable. - -The DefaultParser should be able to handle most situations currently, -however, there are known weakness's in the approach but as it stands, -it is better then other examples I have seen. - -DefaultParser - Tested on mc-central, should work decent globally -""" - -# TODO Parse banner messages, example: https://gyazo.com/c0a4cfee23a31fe8b6e4c7c7848e5e5a - - -def DefaultParser(data): - try: - # Convert to valid python dict - data = json.loads(data) - - # Create the prefix & text - prefixing = True - data = data["extra"] - stringDict = {"prefix": [], "message": []} - dm = False - - if isinstance(data[len(data) - 1], str): - # Given the last item is a string, rather then dictionary - # we can safely assume that this is in fact a /msg - dm = True - - for i, item in enumerate(data): - # Remove minecraft character stuff - if dm and i == len(data) - 1: - stringDict["message"].append(item) - continue - - text = re.sub( - r"\§c|\§f|\§b|\§d|\§a|\§1|\§2|\§3|\§4|\§5|\§6|\§7|\§8|\§9|\§0", - "", - item["text"], - ) - - if text.lstrip().rstrip() == ":" and prefixing: - # No longer need to handle the before message - prefixing = False - continue - elif prefixing: - stringDict["prefix"].append(text) - elif not prefixing: - if "extra" in item: - # Chat parsing for text means this is most likely another nested dict in list situation - if len(item["extra"]) > 0: - if "text" in item["extra"][0]: - text = item["extra"][0]["text"] - stringDict["message"].append(text) - - prefix = "".join(stringDict["prefix"]) - text = " ".join(stringDict["message"]).rstrip().lstrip() - - if len(prefix) > 0 and len(text) > 0: - message = ": ".join([prefix, text]) - elif len(prefix) > 0: - message = prefix - elif len(text) > 0: - message = text - - message = message.lstrip().rstrip() - - return message - - except Exception as e: - # print(f"Unable to parse: {data}\nException: {e}") - return False diff --git a/examples/Player.py b/examples/Player.py deleted file mode 100644 index a88ad7e..0000000 --- a/examples/Player.py +++ /dev/null @@ -1,232 +0,0 @@ -import re -import time -import asyncio -from concurrent.futures.thread import ThreadPoolExecutor - -from minecraft import authentication -from minecraft.exceptions import YggdrasilError -from minecraft.networking.connection import Connection -from minecraft.networking.packets import serverbound, clientbound - -from Parsers import DefaultParser - - -class Player: - """ - A class built to handle all required actions to maintain: - - Gaining auth tokens, and connecting to online minecraft servers. - - Clientbound chat - - Serverbound chat - - Warnings - -------- - This class explicitly expects a username & password, then expects to - be able to connect to a server in online mode. - If you wish to add different functionality please - """ - - def __init__(self, username, password, *, admins=None): - """ - Initialize things such as kickout, admins and auth - - Parameters - ---------- - username : String - Used for authentication - password : String - Used for authentication - admins : list, optional - The minecraft accounts to auto accept tpa's requests from - - Raises - ------ - YggdrasilError : minecraft.exceptions - Username or Password was incorrect - - """ - self.kickout = False - self.admins = [] if admins is None else admins - - self.auth_token = authentication.AuthenticationToken() - self.auth_token.authenticate(username, password) - - def Parser(self, data): - """ - Converts the chat packet received from the server - into human readable strings - - Parameters - ---------- - data : JSON - The chat data json receive from the server - - Returns - ------- - message : String - The text received from the server in human readable form - - """ - message = DefaultParser(data) # This is where you would call other parsers - - if not message: - return False - - if "teleport" in message.lower(): - self.HandleTpa(message) - - return message - - def HandleTpa(self, message): - """ - Using the given message, figure out whether or not to accept the tpa - - Parameters - ---------- - message : String - The current chat, where 'tpa' was found in message.lower() - - """ - try: - found = re.search( - "(.+?) has requested that you teleport to them.", message - ).group(1) - if found in self.admins: - self.SendChat("/tpyes") - return - except AttributeError: - pass - - try: - found = re.search("(.+?) has requested to teleport to you.", message).group( - 1 - ) - if found in self.admins: - self.SendChat("/tpyes") - return - except AttributeError: - pass - - def SendChat(self, msg): - """ - Send a given message to the server - - Parameters - ---------- - msg : String - The message to send to the server - - """ - msg = str(msg) - if len(msg) > 0: - packet = serverbound.play.ChatPacket() - packet.message = msg - self.connection.write_packet(packet) - - def ReceiveChat(self, chat_packet): - """ - The listener for ClientboundChatPackets - - Parameters - ---------- - chat_packet : ClientboundChatPacket - The incoming chat packet - chat_packet.json : JSON - The chat packet to pass of to our Parser for handling - - """ - message = self.Parser(chat_packet.json_data) - if not message: - # This means our Parser failed lol - print("Parser failed") - return - - print(message) - - def SetServer(self, ip, port=25565, handler=None): - """ - Sets the server, ready for connection - - Parameters - ---------- - ip : str - The server to connect to - port : int, optional - The port to connect on - handler : Function pointer, optional - Points to the function used to handle Clientbound chat packets - - """ - handler = handler or self.ReceiveChat - - self.ip = ip - self.port = port - self.connection = Connection( - ip, port, auth_token=self.auth_token, handle_exception=print - ) - - self.connection.register_packet_listener( - handler, clientbound.play.ChatMessagePacket - ) - - self.connection.exception_handler(print) - - def Connect(self): - """ - Actually connect to the server for this player and maintain said connection - - """ - self.connection.connect() - - print(f"Connected to server with: {self.auth_token.username}") - - count = 0 - while True: - time.sleep(1) - count += 1 - if self.kickout: - break - elif count == 50: - break - - def Disconnect(self): - """ - In order to disconnect the client, and break the blocking loop - this method must be called - - """ - self.kickout = True - self.connection.disconnect() - - -async def Main(): - try: - player = Player("Account Email/Username", "Account Password") - except YggdrasilError as e: - # Authentication Error - print("Incorrect Login", e) - return - - player.SetServer("Server to connect to.") - - # We do this to ensure it is non blocking as Connect() is a - # forever loop used to maintain a connection to a server - executor = ThreadPoolExecutor() - executor.submit(player.Connect) - - # Forever do things unless the user wants us to logout - while True: - message = input("What should I do/say?\n") - - # Disconnect the client from the server before finishing everything up - if message.lower() in ["logout", "disconnected", "exit"]: - player.Disconnect() - print("Disconnected") - return - - # Send the message to the server via the player - player.SendChat(message) - - -# Simply run our program -if __name__ == "__main__": - asyncio.run(Main())