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