def handle_chat(pak, state): data = json.loads(pak.json_data) if pak.position == clientbound.play.ChatMessagePacket.Position.SYSTEM and ( data.get("translate", "") == "commands.message.display.incoming" or data.get("translate", "") == "chat.type.announcement"): # Whispers and such name = data["with"][0]["text"] message = data["with"][1]["text"] elif pak.position == clientbound.play.ChatMessagePacket.Position.CHAT: # Chat message name = data["with"][0]["insertion"] message = data["with"][1] else: return if message != state["sleep_command"]: return print_timestamped("Sleep requested by " + name) # Notify main loop that sleep has been requested state["sleep_requested"] = True # Disconnected from server state["connection"].disconnect(immediate=True) state["connected"] = False
def setup_connection(address, port, version, auth_token, state, username=None): connection = Connection( address, port, auth_token=auth_token, initial_version=version, username=username, handle_exception=partial(handle_exception, state=state), ) print_timestamped(f"Connecting to {address}:{port}") # Cast rod on join connection.register_packet_listener(partial(handle_join_game, state=state), clientbound.play.JoinGamePacket) # Reel in and recast rod on bobber splash connection.register_packet_listener( partial(handle_sound_play, state=state), clientbound.play.SoundEffectPacket) if state["sleep_helper"]: # Disconnect for a while when people need to sleep connection.register_packet_listener(partial(handle_chat, state=state), clientbound.play.ChatMessagePacket) # Handle disconnects connection.register_packet_listener(partial(handle_dc, state=state), clientbound.play.DisconnectPacket) connection.register_packet_listener(partial(handle_dc, state=state), clientbound.login.DisconnectPacket) return connection
def handle_exception(exc, sysstat, state): """Handle exceptions in the connection""" if isinstance(exc, KeyboardInterrupt): return print_timestamped("Exception handled: ", exc) print_timestamped(sysstat) # Disconnected from server - restart connection state["connection"].disconnect(immediate=True) state["connected"] = False
def handle_sound_play(pak, state): if pak.sound_id != state["bobber_splash_id"]: return # Reel in and cast use_item(state) use_item(state) state["recently_cast"] = True state["amount_caught"] += 1 if state["print_output"]: print_timestamped("Caught one!")
def handle_join_game(pak, state): print_timestamped("Connection established") # Cast the rod use_item(state) # Greet the server if state["greet_message"] != "" and state["greet_message"] is not None: greet_packet = serverbound.play.ChatPacket() greet_packet.message = state["greet_message"] state["connection"].write_packet(greet_packet) # Inform the server of the sleep command if state["sleep_helper"]: sleep_packet = serverbound.play.ChatPacket() sleep_packet.message = state["sleep_message"] state["connection"].write_packet(sleep_packet)
def loop_realm_address(auth_token, realm_name): # Getting ip and port of realm until successful while True: try: address, port = get_realm_address( name=auth_token.profile.name, uuid=auth_token.profile.id_, access_token=auth_token.access_token, realm_name=realm_name, ) except ValueError as e: # Could not find realm with given name print_timestamped(str(e)) sys.exit(1) except RuntimeError as e: # Error in request print_timestamped(str(e)) sleep(5) else: # Got ip and port return address, port
def main(): options = get_options() try: CONFIG = read_config(fp=options.config) except RuntimeError as e: print(e) sys.exit(1) finally: options.config.close() OPTIONS = CONFIG["options"] HOST = CONFIG["host"] # Get sound id and close file pointer splash_id = get_bobber_splash_id(HOST["version"], fp=options.gamedata) # Read stored profile has_token, user_data = read_profile(OPTIONS["profile_path"]) if not HOST["offline"]: # Validate/refresh token if has_token: auth_token = create_auth_token(user_data) # Client has no token, or the token was invalid if not has_token or not auth_token: print("Authenticate with username+password") auth_token = authenticate_user(user_data) # Update profile and write to disk update_profile(OPTIONS["profile_path"], user_data, auth_token) username = auth_token.profile.name else: print("Playing in offline mode - skipping authentication") if OPTIONS.get("username", None) is None: OPTIONS["username"] = input( "What username do you want to play with? ") auth_token = None username = OPTIONS["username"] # Program state start_time = datetime.now() timeouts = [] # Stores the potential durability that has been taken off the rod due to timeouts # minus the durability recovered by mending durability_count = 0 state = { "amount_caught": 0, "recently_cast": False, "sleep_requested": False, "connection": None, "connected": False, "bobber_splash_id": splash_id, } state.update(OPTIONS) try: # Reconnect indefinitely while True: try: address, port = get_host_address(HOST, auth_token) except RuntimeError as e: print(e) sys.exit(1) # Establish connection state["connection"] = setup_connection( address=address, port=port, version=HOST["version"], auth_token=auth_token, state=state, username=username, ) try: state["connection"].connect() except ConnectionRefusedError as e: print(e) sys.exit(1) state["connected"] = True while state["connected"]: # Check for timeouts, fishing is handled by eventlisteners state["recently_cast"] = False check_for_sleep(OPTIONS["fish_timeout"], state) if not state["recently_cast"]: # Timed out if durability_count >= OPTIONS["durability_threshold"]: # Log out to save the rod print_timestamped( "Too many timeouts; rod has, at worst, taken " f"~{durability_count} " "points of durability. Logging out to save it.") # Ugly hack to display results of session before exiting raise EndFishingSession print_timestamped( f"Timed out; more than {OPTIONS['fish_timeout']} seconds " "since last catch. Using the rod once.") timeouts.append(datetime.now()) use_item(state) # Reeling in a mob costs 5 durability # This can be done at most every other use of the rod durability_count += 5 / 2 else: # Fishing grants 1-6 exp which each gives 2 durability # The rod cannot be repaired past fully repaired durability_count = max(0, durability_count - 2) except (KeyboardInterrupt, EndFishingSession): print_timestamped("Ending session") state["connection"].disconnect() time_diff = datetime.now() - start_time seconds = time_diff.days * 24 * 60 * 60 + time_diff.seconds print("Time elapsed:", time_diff) print("Fish caught: " + str(state["amount_caught"])) print("Fish/minute: " + str(state["amount_caught"] / seconds * 60)) if state["amount_caught"] != 0: print("Seconds/fish: " + str(seconds / state["amount_caught"])) if len(timeouts) != 0: print("Timeouts:") for t in timeouts: print("\t" + str(t)) sys.exit()
def handle_dc(pak, state): print_timestamped("DC-packet recieved, id: " + str(pak.id)) # Disconnected from server - restart connection state["connection"].disconnect(immediate=True) state["connected"] = False