reorganize Minecraft client internal structure, add missing error handling in update_mod
This commit is contained in:
parent
8d4be10fd7
commit
fa8531022d
|
@ -1,18 +1,21 @@
|
||||||
import argparse
|
import argparse
|
||||||
import os, sys
|
import os, sys
|
||||||
import re
|
import re
|
||||||
import requests
|
|
||||||
import atexit
|
import atexit
|
||||||
import logging
|
|
||||||
from subprocess import Popen
|
from subprocess import Popen
|
||||||
from shutil import copyfile
|
from shutil import copyfile
|
||||||
from base64 import b64decode
|
from base64 import b64decode
|
||||||
from json import loads
|
from json import loads
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
import Utils
|
import Utils
|
||||||
|
|
||||||
atexit.register(input, "Press enter to exit.")
|
atexit.register(input, "Press enter to exit.")
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
# 1 or more digits followed by m or g, then optional b
|
||||||
|
max_heap_re = re.compile(r"^\d+[mMgG][bB]?$")
|
||||||
|
|
||||||
|
|
||||||
def prompt_yes_no(prompt):
|
def prompt_yes_no(prompt):
|
||||||
yes_inputs = {'yes', 'ye', 'y'}
|
yes_inputs = {'yes', 'ye', 'y'}
|
||||||
|
@ -26,63 +29,51 @@ def prompt_yes_no(prompt):
|
||||||
else:
|
else:
|
||||||
print('Please respond with "y" or "n".')
|
print('Please respond with "y" or "n".')
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("apmc_file", default=None, help="Path to an Archipelago Minecraft data file (.apmc)")
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
# Find Forge jar file; raise error if not found
|
||||||
options = Utils.get_options()
|
def find_forge_jar(forge_dir):
|
||||||
max_heap_re = re.compile(r"^\d+[mMgG][bB]?$")
|
|
||||||
|
|
||||||
apmc_file = args.apmc_file
|
|
||||||
forge_dir = options["minecraft_options"]["forge_directory"]
|
|
||||||
max_heap = options["minecraft_options"]["max_heap_size"]
|
|
||||||
|
|
||||||
if apmc_file is not None and not os.path.isfile(apmc_file):
|
|
||||||
raise FileNotFoundError(f"Path {apmc_file} does not exist or could not be accessed.")
|
|
||||||
if not os.path.isdir(forge_dir):
|
|
||||||
raise NotADirectoryError(f"Path {forge_dir} does not exist.")
|
|
||||||
if not max_heap_re.match(max_heap):
|
|
||||||
raise Exception(f"Max heap size {max_heap} in incorrect format. Use a number followed by M or G, e.g. 512M or 2G.")
|
|
||||||
|
|
||||||
# Find forge .jar
|
|
||||||
forge_server = None
|
|
||||||
for entry in os.scandir(forge_dir):
|
for entry in os.scandir(forge_dir):
|
||||||
if ".jar" in entry.name and "forge" in entry.name:
|
if ".jar" in entry.name and "forge" in entry.name:
|
||||||
forge_server = entry.name
|
print(f"Found forge .jar: {entry.name}")
|
||||||
print(f"Found forge .jar: {forge_server}")
|
return entry.name
|
||||||
if forge_server is None:
|
raise FileNotFoundError(f"Could not find forge .jar in {forge_dir}.")
|
||||||
raise FileNotFoundError(f"Could not find forge .jar in {forge_dir}.")
|
|
||||||
|
|
||||||
# Find current randomizer mod, make mod dir if it doesn't already exist
|
|
||||||
|
# Create mods folder if needed; find AP randomizer jar; return None if not found.
|
||||||
|
def find_ap_randomizer_jar(forge_dir):
|
||||||
mods_dir = os.path.join(forge_dir, 'mods')
|
mods_dir = os.path.join(forge_dir, 'mods')
|
||||||
ap_randomizer = None
|
|
||||||
if os.path.isdir(mods_dir):
|
if os.path.isdir(mods_dir):
|
||||||
ap_mod_re = re.compile(r"^aprandomizer-[\d\.]+\.jar$")
|
ap_mod_re = re.compile(r"^aprandomizer-[\d\.]+\.jar$")
|
||||||
for entry in os.scandir(mods_dir):
|
for entry in os.scandir(mods_dir):
|
||||||
match = ap_mod_re.match(entry.name)
|
match = ap_mod_re.match(entry.name)
|
||||||
if ap_mod_re.match(entry.name):
|
if match:
|
||||||
ap_randomizer = match.group()
|
print(f"Found AP randomizer mod: {match.group()}")
|
||||||
print(f"Found AP randomizer mod: {ap_randomizer}")
|
return match.group()
|
||||||
break
|
return None
|
||||||
else:
|
else:
|
||||||
os.mkdir(mods_dir)
|
os.mkdir(mods_dir)
|
||||||
print(f"Created mods folder in {forge_dir}")
|
print(f"Created mods folder in {forge_dir}")
|
||||||
|
return None
|
||||||
|
|
||||||
# If given an apmc file, remove any apmc files in APData and copy the new one in
|
|
||||||
if apmc_file is not None:
|
|
||||||
apdata_dir = os.path.join(forge_dir, 'APData')
|
|
||||||
if not os.path.isdir(apdata_dir):
|
|
||||||
os.mkdir(apdata_dir)
|
|
||||||
print(f"Created APData folder in {forge_dir}")
|
|
||||||
for entry in os.scandir(apdata_dir):
|
|
||||||
if ".apmc" in entry.name and entry.is_file():
|
|
||||||
os.remove(entry.path)
|
|
||||||
print(f"Removed existing .apmc files in {apdata_dir}")
|
|
||||||
copyfile(apmc_file, os.path.join(apdata_dir, os.path.basename(apmc_file)))
|
|
||||||
print(f"Copied new .apmc file to {apdata_dir}")
|
|
||||||
|
|
||||||
# Download new client if needed
|
# Create APData folder if needed; clean .apmc files from APData; copy given .apmc into directory.
|
||||||
|
def replace_apmc_files(forge_dir, apmc_file):
|
||||||
|
if apmc_file is None:
|
||||||
|
return
|
||||||
|
apdata_dir = os.path.join(forge_dir, 'APData')
|
||||||
|
if not os.path.isdir(apdata_dir):
|
||||||
|
os.mkdir(apdata_dir)
|
||||||
|
print(f"Created APData folder in {forge_dir}")
|
||||||
|
for entry in os.scandir(apdata_dir):
|
||||||
|
if ".apmc" in entry.name and entry.is_file():
|
||||||
|
os.remove(entry.path)
|
||||||
|
print(f"Removed existing .apmc files in {apdata_dir}")
|
||||||
|
copyfile(apmc_file, os.path.join(apdata_dir, os.path.basename(apmc_file)))
|
||||||
|
print(f"Copied {apmc_file} to {apdata_dir}")
|
||||||
|
|
||||||
|
|
||||||
|
# Check mod version, download new mod from GitHub releases page if needed.
|
||||||
|
def update_mod(forge_dir, ap_randomizer):
|
||||||
client_releases_endpoint = "https://api.github.com/repos/KonoTyran/Minecraft_AP_Randomizer/releases"
|
client_releases_endpoint = "https://api.github.com/repos/KonoTyran/Minecraft_AP_Randomizer/releases"
|
||||||
resp = requests.get(client_releases_endpoint)
|
resp = requests.get(client_releases_endpoint)
|
||||||
if resp.status_code == 200: # OK
|
if resp.status_code == 200: # OK
|
||||||
|
@ -106,10 +97,18 @@ if __name__ == '__main__':
|
||||||
os.remove(old_ap_mod)
|
os.remove(old_ap_mod)
|
||||||
print(f"Removed old mod file from {old_ap_mod}")
|
print(f"Removed old mod file from {old_ap_mod}")
|
||||||
else:
|
else:
|
||||||
print(f"Error retrieving the randomizer mod (status code {apmod_resp.status_code}).\nPlease report this issue on the Archipelago Discord server.")
|
print(f"Error retrieving the randomizer mod (status code {apmod_resp.status_code}).")
|
||||||
|
print(f"Please report this issue on the Archipelago Discord server.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
print(f"Error checking for randomizer mod updates (status code {resp.status_code}).")
|
||||||
|
print(f"If this was not expected, please report this issue on the Archipelago Discord server.")
|
||||||
|
if not prompt_yes_no("Continue anyways?"):
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
# Run forge server
|
|
||||||
|
# Run the Forge server. Return process object
|
||||||
|
def run_forge_server(forge_dir, forge_server, heap_arg):
|
||||||
java_exe = os.path.abspath(os.path.join('jre8', 'bin', 'java.exe'))
|
java_exe = os.path.abspath(os.path.join('jre8', 'bin', 'java.exe'))
|
||||||
if not os.path.isfile(java_exe):
|
if not os.path.isfile(java_exe):
|
||||||
java_exe = "java" # try to fall back on java in the PATH
|
java_exe = "java" # try to fall back on java in the PATH
|
||||||
|
@ -122,5 +121,30 @@ if __name__ == '__main__':
|
||||||
argstring = ' '.join([java_exe, heap_arg, "-jar", forge_server, "-nogui"])
|
argstring = ' '.join([java_exe, heap_arg, "-jar", forge_server, "-nogui"])
|
||||||
print(f"Running Forge server: {argstring}")
|
print(f"Running Forge server: {argstring}")
|
||||||
os.chdir(forge_dir)
|
os.chdir(forge_dir)
|
||||||
server = Popen(argstring)
|
return Popen(argstring)
|
||||||
server.wait()
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("apmc_file", default=None, help="Path to an Archipelago Minecraft data file (.apmc)")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
options = Utils.get_options()
|
||||||
|
|
||||||
|
apmc_file = args.apmc_file
|
||||||
|
forge_dir = options["minecraft_options"]["forge_directory"]
|
||||||
|
max_heap = options["minecraft_options"]["max_heap_size"]
|
||||||
|
|
||||||
|
if apmc_file is not None and not os.path.isfile(apmc_file):
|
||||||
|
raise FileNotFoundError(f"Path {apmc_file} does not exist or could not be accessed.")
|
||||||
|
if not os.path.isdir(forge_dir):
|
||||||
|
raise NotADirectoryError(f"Path {forge_dir} does not exist or could not be accessed.")
|
||||||
|
if not max_heap_re.match(max_heap):
|
||||||
|
raise Exception(f"Max heap size {max_heap} in incorrect format. Use a number followed by M or G, e.g. 512M or 2G.")
|
||||||
|
|
||||||
|
forge_server = find_forge_jar(forge_dir)
|
||||||
|
ap_randomizer = find_ap_randomizer_jar(forge_dir)
|
||||||
|
replace_apmc_files(forge_dir, apmc_file)
|
||||||
|
update_mod(forge_dir, ap_randomizer)
|
||||||
|
server_process = run_forge_server(forge_dir, forge_server, max_heap)
|
||||||
|
server_process.wait()
|
||||||
|
|
Loading…
Reference in New Issue