diff --git a/config.json b/config.json index 8e70ef4..99567d8 100644 --- a/config.json +++ b/config.json @@ -30,6 +30,9 @@ "remove_items": true, "remove_bats": true, "remove_phantoms": true, + "view_distance": 16, + "chat_colors": false, + "right_main_hand": true, "__5__": "-------- PCRC Whitelist --------", "enabled": false, @@ -37,4 +40,4 @@ "Fallen_Breath", "Steve" ] -} \ No newline at end of file +} diff --git a/utils/config.py b/utils/config.py index 448fe43..caca965 100644 --- a/utils/config.py +++ b/utils/config.py @@ -9,6 +9,7 @@ "__2__": "-------- Account and Server --------", "online_mode": false, + "yggdrasil_server": "", "username": "bot_PCRC", "password": "secret", "address": "localhost", @@ -46,6 +47,7 @@ SettableOptions = [ 'language', + 'yggdrasil_server', 'server_name', 'minimal_packets', 'daytime', @@ -120,6 +122,7 @@ def secret(text): messages.append(f"Debug mode = {self.get('debug_mode')}") messages.append('-------- Account and Server --------') messages.append(f"Online mode = {self.get('online_mode')}") + messages.append(f"Yggdrasil server = {self.get('yggdrasil_server')}") messages.append(f"User name = {secret(self.get('username'))}") messages.append(f"Password = ******") messages.append(f"Server address = {self.get('address')}") diff --git a/utils/pycraft/authentication.py b/utils/pycraft/authentication.py index e78e875..826acd8 100644 --- a/utils/pycraft/authentication.py +++ b/utils/pycraft/authentication.py @@ -11,6 +11,34 @@ HEADERS = {"content-type": CONTENT_TYPE} +class YggdrasilServer(object): + def __init__(self, url): + if not url == None: + self.url = _get_yggdrasil_url(url) + + def request_auth_server(self, endpoint, data): + return _make_request(self.url + "/authserver", endpoint, data) + + def request_session_server(self, endpoint, data): + return _make_request(self.url + "/sessionserver/session/minecraft", endpoint, data) + + +def _get_yggdrasil_url(url): + # TODO impl ALI + return url + + +class MojangServer(YggdrasilServer): + def __init__(self): + super().__init__(None) + + def request_auth_server(self, endpoint, data): + return _make_request(AUTH_SERVER, endpoint, data) + + def request_session_server(self, endpoint, data): + return _make_request(SESSION_SERVER, endpoint, data) + + class Profile(object): """ Container class for a MineCraft Selected profile. @@ -48,7 +76,7 @@ class AuthenticationToken(object): AGENT_NAME = "Minecraft" AGENT_VERSION = 1 - def __init__(self, username=None, access_token=None, client_token=None): + def __init__(self, username=None, access_token=None, client_token=None, yggdrasil_server=MojangServer()): """ Constructs an `AuthenticationToken` based on `access_token` and `client_token`. @@ -63,6 +91,7 @@ def __init__(self, username=None, access_token=None, client_token=None): self.username = username self.access_token = access_token self.client_token = client_token + self.yggdrasil_server = yggdrasil_server self.profile = Profile() @property @@ -119,7 +148,8 @@ def authenticate(self, username, password, invalidate_previous=False): # is `None` generate a `client_token` using uuid4 payload["clientToken"] = self.client_token or uuid.uuid4().hex - res = _make_request(AUTH_SERVER, "authenticate", payload) + res = self.yggdrasil_server.request_auth_server( + "authenticate", payload) _raise_from_response(res) @@ -154,9 +184,9 @@ def refresh(self): if self.client_token is None: raise ValueError("'client_token' is not set!") - res = _make_request(AUTH_SERVER, - "refresh", {"accessToken": self.access_token, - "clientToken": self.client_token}) + res = self.yggdrasil_server.request_auth_server("refresh", + {"accessToken": self.access_token, + "clientToken": self.client_token}) _raise_from_response(res) @@ -186,8 +216,8 @@ def validate(self): if self.access_token is None: raise ValueError("'access_token' not set!") - res = _make_request(AUTH_SERVER, "validate", - {"accessToken": self.access_token}) + res = self.yggdrasil_server.request_auth_server("validate", + {"accessToken": self.access_token}) # Validate returns 204 to indicate success # http://wiki.vg/Authentication#Response_3 @@ -195,7 +225,7 @@ def validate(self): return True @staticmethod - def sign_out(username, password): + def sign_out(username, password, yggdrasil_server=MojangServer()): """ Invalidates `access_token`s using an account's `username` and `password`. @@ -211,8 +241,8 @@ def sign_out(username, password): Raises: pycraft.exceptions.YggdrasilError """ - res = _make_request(AUTH_SERVER, "signout", - {"username": username, "password": password}) + res = yggdrasil_server.request_auth_server("signout", + {"username": username, "password": password}) if _raise_from_response(res) is None: return True @@ -228,9 +258,9 @@ def invalidate(self): Raises: :class:`pycraft.exceptions.YggdrasilError` """ - res = _make_request(AUTH_SERVER, "invalidate", - {"accessToken": self.access_token, - "clientToken": self.client_token}) + res = self.yggdrasil_server.request_auth_server("invalidate", + {"accessToken": self.access_token, + "clientToken": self.client_token}) if res.status_code != 204: _raise_from_response(res) @@ -255,10 +285,10 @@ def join(self, server_id): err = "AuthenticationToken hasn't been authenticated yet!" raise YggdrasilError(err) - res = _make_request(SESSION_SERVER, "join", - {"accessToken": self.access_token, - "selectedProfile": self.profile.to_dict(), - "serverId": server_id}) + res = self.yggdrasil_server.request_session_server("join", + {"accessToken": self.access_token, + "selectedProfile": self.profile.id_, #this is a hidden bug in pyCraft + "serverId": server_id}) if res.status_code != 204: _raise_from_response(res) diff --git a/utils/recorder.py b/utils/recorder.py index e78bced..56e30a2 100644 --- a/utils/recorder.py +++ b/utils/recorder.py @@ -54,7 +54,12 @@ def __init__(self, config_file, translation_folder): ) else: self.logger.log("Login in online mode") - auth_token = authentication.AuthenticationToken() + yggdrasil_server = self.config.get('yggdrasil_server') + if yggdrasil_server == "": + yggdrasil_server = authentication.MojangServer() + else: + yggdrasil_server = authentication.YggdrasilServer(yggdrasil_server) + auth_token = authentication.AuthenticationToken(yggdrasil_server = yggdrasil_server) auth_token.authenticate(self.config.get('username'), self.config.get('password')) self.logger.log("Logged in as %s" % auth_token.profile.name) self.config.set_value('username', auth_token.profile.name) @@ -113,6 +118,17 @@ def onGameJoin(self, packet): self.logger.log('PCRC bot joined the server') self.online = True self.chat(self.translation('OnGameJoin')) + client_settings = serverbound.play.ClientSettingsPacket() + client_settings.locale = self.config.get('language') + client_settings.view_distance = self.config.get('view_distance') + client_settings.chat_mode = client_settings.ChatMode.FULL + client_settings.chat_colors = self.config.get('chat_colors') + client_settings.displayed_skin_parts = client_settings.SkinParts.ALL + if self.config.get('right_main_hand'): + client_settings.main_hand = client_settings.Hand.RIGHT + else: + client_settings.main_hand = client_settings.Hand.LEFT + self.connection.write_packet(client_settings) def onDisconnect(self, packet): self.logger.log('PCRC disconnected from the server, reason = {}'.format(packet.json_data))