Add examples usages.

This commit is contained in:
skelmis 2020-08-27 23:37:49 +12:00
parent 09546dcd26
commit 42b911342b
2 changed files with 0 additions and 307 deletions

View File

@ -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

View File

@ -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())