| import os |
| import re |
|
|
| import minecraft_launcher_lib |
| import sys |
| import utils as U |
|
|
| from .process_monitor import SubprocessMonitor |
|
|
|
|
| class MinecraftInstance: |
| def __init__( |
| self, |
| client_id, |
| redirect_url, |
| secret_value, |
| version, |
| mineflayer, |
| log_path="logs", |
| ): |
| self.client_id = client_id |
| self.redirect_url = redirect_url |
| self.secret_value = secret_value |
| self.version = version |
| self.log_path = log_path |
| self.mc_dir = minecraft_launcher_lib.utils.get_minecraft_directory() |
| self.port = None |
|
|
| def stop_mineflayer(): |
| print("Stopping mineflayer") |
| try: |
| mineflayer.stop() |
| except Exception as e: |
| print(e) |
|
|
| self.mc_command = self.get_mc_command() |
| self.mc_process = SubprocessMonitor( |
| commands=self.mc_command, |
| name="minecraft", |
| ready_match=r"Started serving on (\d+)", |
| log_path=self.log_path, |
| callback=stop_mineflayer, |
| callback_match=r"\[Server thread/INFO\]: bot left the game", |
| finished_callback=stop_mineflayer, |
| ) |
|
|
| def get_mineflayer_process(self, server_port): |
| U.f_mkdir(self.log_path, "../mineflayer") |
| file_path = os.path.abspath(os.path.dirname(__file__)) |
| return SubprocessMonitor( |
| commands=[ |
| "node", |
| U.f_join(file_path, "mineflayer/index.js"), |
| str(server_port), |
| ], |
| name="mineflayer", |
| ready_match=r"Server started on port (\d+)", |
| log_path=U.f_join(self.log_path, "mineflayer"), |
| ) |
|
|
| def get_mc_command(self): |
| file_path = os.path.abspath(os.path.dirname(__file__)) |
| if not U.f_exists(file_path, "config.json"): |
| ( |
| login_url, |
| state, |
| code_verifier, |
| ) = minecraft_launcher_lib.microsoft_account.get_secure_login_data( |
| self.client_id, self.redirect_url |
| ) |
| print( |
| f"Please open {login_url} in your browser and copy the url you are redirected into the prompt below." |
| ) |
| code_url = input() |
|
|
| try: |
| auth_code = ( |
| minecraft_launcher_lib.microsoft_account.parse_auth_code_url( |
| code_url, state |
| ) |
| ) |
| except AssertionError: |
| print("States do not match!") |
| sys.exit(1) |
| except KeyError: |
| print("Url not valid") |
| sys.exit(1) |
|
|
| login_data = minecraft_launcher_lib.microsoft_account.complete_login( |
| self.client_id, |
| self.secret_value, |
| self.redirect_url, |
| auth_code, |
| code_verifier, |
| ) |
|
|
| options = { |
| "username": login_data["name"], |
| "uuid": login_data["id"], |
| "token": login_data["access_token"], |
| } |
| U.json_dump(options, file_path, "config.json") |
| print(f"Login success, save to {U.f_join(file_path, 'config.json')}") |
|
|
| options = U.json_load(file_path, "config.json") |
| mc_command = minecraft_launcher_lib.command.get_minecraft_command( |
| self.version, self.mc_dir, options |
| ) |
|
|
| return mc_command |
|
|
| def run(self): |
| self.mc_process.run() |
| pattern = r"Started serving on (\d+)" |
| match = re.search(pattern, self.mc_process.ready_line) |
| if match: |
| self.port = int(match.group(1)) |
| print("The mc server is listening on port", self.port) |
| else: |
| raise RuntimeError("Port not found") |
|
|
| def stop(self): |
| self.mc_process.stop() |
|
|
| @property |
| def is_running(self): |
| return self.mc_process.is_running |
|
|