Minecraft client first pass
This commit is contained in:
		
							parent
							
								
									285b9e12eb
								
							
						
					
					
						commit
						8d4be10fd7
					
				| 
						 | 
					@ -0,0 +1,126 @@
 | 
				
			||||||
 | 
					import argparse
 | 
				
			||||||
 | 
					import os, sys
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					import requests
 | 
				
			||||||
 | 
					import atexit
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					from subprocess import Popen
 | 
				
			||||||
 | 
					from shutil import copyfile
 | 
				
			||||||
 | 
					from base64 import b64decode
 | 
				
			||||||
 | 
					from json import loads
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Utils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					atexit.register(input, "Press enter to exit.")
 | 
				
			||||||
 | 
					logger = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def prompt_yes_no(prompt):
 | 
				
			||||||
 | 
					    yes_inputs = {'yes', 'ye', 'y'}
 | 
				
			||||||
 | 
					    no_inputs = {'no', 'n'}
 | 
				
			||||||
 | 
					    while True:
 | 
				
			||||||
 | 
					        choice = input(prompt + " [y/n] ").lower()
 | 
				
			||||||
 | 
					        if choice in yes_inputs: 
 | 
				
			||||||
 | 
					            return True
 | 
				
			||||||
 | 
					        elif choice in no_inputs: 
 | 
				
			||||||
 | 
					            return False
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            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()
 | 
				
			||||||
 | 
					    options = Utils.get_options()
 | 
				
			||||||
 | 
					    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):
 | 
				
			||||||
 | 
					        if ".jar" in entry.name and "forge" in entry.name:
 | 
				
			||||||
 | 
					            forge_server = entry.name
 | 
				
			||||||
 | 
					            print(f"Found forge .jar: {forge_server}")
 | 
				
			||||||
 | 
					    if forge_server is None:
 | 
				
			||||||
 | 
					        raise FileNotFoundError(f"Could not find forge .jar in {forge_dir}.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Find current randomizer mod, make mod dir if it doesn't already exist
 | 
				
			||||||
 | 
					    mods_dir = os.path.join(forge_dir, 'mods')
 | 
				
			||||||
 | 
					    ap_randomizer = None
 | 
				
			||||||
 | 
					    if os.path.isdir(mods_dir):
 | 
				
			||||||
 | 
					        ap_mod_re = re.compile(r"^aprandomizer-[\d\.]+\.jar$")
 | 
				
			||||||
 | 
					        for entry in os.scandir(mods_dir):
 | 
				
			||||||
 | 
					            match = ap_mod_re.match(entry.name)
 | 
				
			||||||
 | 
					            if ap_mod_re.match(entry.name):
 | 
				
			||||||
 | 
					                ap_randomizer = match.group()
 | 
				
			||||||
 | 
					                print(f"Found AP randomizer mod: {ap_randomizer}")
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        os.mkdir(mods_dir)
 | 
				
			||||||
 | 
					        print(f"Created mods folder in {forge_dir}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # 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
 | 
				
			||||||
 | 
					    client_releases_endpoint = "https://api.github.com/repos/KonoTyran/Minecraft_AP_Randomizer/releases"
 | 
				
			||||||
 | 
					    resp = requests.get(client_releases_endpoint)
 | 
				
			||||||
 | 
					    if resp.status_code == 200:  # OK
 | 
				
			||||||
 | 
					        latest_release = resp.json()[0]
 | 
				
			||||||
 | 
					        if ap_randomizer != latest_release['assets'][0]['name']:
 | 
				
			||||||
 | 
					            print(f"A new release of the Minecraft AP randomizer mod was found: {latest_release['assets'][0]['name']}")
 | 
				
			||||||
 | 
					            if ap_randomizer is not None:
 | 
				
			||||||
 | 
					                print(f"Your current mod is {ap_randomizer}.")
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                print(f"You do not have the AP randomizer mod installed.")
 | 
				
			||||||
 | 
					            if prompt_yes_no("Would you like to update?"):
 | 
				
			||||||
 | 
					                old_ap_mod = os.path.join(forge_dir, 'mods', ap_randomizer) if ap_randomizer is not None else None
 | 
				
			||||||
 | 
					                new_ap_mod = os.path.join(forge_dir, 'mods', latest_release['assets'][0]['name'])
 | 
				
			||||||
 | 
					                print("Downloading AP randomizer mod. This may take a moment...")
 | 
				
			||||||
 | 
					                apmod_resp = requests.get(latest_release['assets'][0]['browser_download_url'])
 | 
				
			||||||
 | 
					                if apmod_resp.status_code == 200: 
 | 
				
			||||||
 | 
					                    with open(new_ap_mod, 'wb') as f:
 | 
				
			||||||
 | 
					                        f.write(apmod_resp.content)
 | 
				
			||||||
 | 
					                        print(f"Wrote new mod file to {new_ap_mod}")
 | 
				
			||||||
 | 
					                    if old_ap_mod is not None:
 | 
				
			||||||
 | 
					                        os.remove(old_ap_mod)
 | 
				
			||||||
 | 
					                        print(f"Removed old mod file from {old_ap_mod}")
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    print(f"Error retrieving the randomizer mod (status code {apmod_resp.status_code}).\nPlease report this issue on the Archipelago Discord server.")
 | 
				
			||||||
 | 
					                    sys.exit(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Run forge server
 | 
				
			||||||
 | 
					    java_exe = os.path.abspath(os.path.join('jre8', 'bin', 'java.exe'))
 | 
				
			||||||
 | 
					    if not os.path.isfile(java_exe):
 | 
				
			||||||
 | 
					        java_exe = "java"  # try to fall back on java in the PATH
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    heap_arg = max_heap_re.match(max_heap).group()
 | 
				
			||||||
 | 
					    if heap_arg[-1] in ['b', 'B']:
 | 
				
			||||||
 | 
					        heap_arg = heap_arg[:-1]
 | 
				
			||||||
 | 
					    heap_arg = "-Xmx" + heap_arg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    argstring = ' '.join([java_exe, heap_arg, "-jar", forge_server, "-nogui"])
 | 
				
			||||||
 | 
					    print(f"Running Forge server: {argstring}")
 | 
				
			||||||
 | 
					    os.chdir(forge_dir)
 | 
				
			||||||
 | 
					    server = Popen(argstring)
 | 
				
			||||||
 | 
					    server.wait()
 | 
				
			||||||
| 
						 | 
					@ -82,4 +82,7 @@ lttp_options:
 | 
				
			||||||
  # Alternatively, a path to a program to open the .sfc file with
 | 
					  # Alternatively, a path to a program to open the .sfc file with
 | 
				
			||||||
  rom_start: true
 | 
					  rom_start: true
 | 
				
			||||||
factorio_options:
 | 
					factorio_options:
 | 
				
			||||||
  executable: "factorio\\bin\\x64\\factorio"
 | 
					  executable: "factorio\\bin\\x64\\factorio"
 | 
				
			||||||
 | 
					minecraft_options: 
 | 
				
			||||||
 | 
					  forge_directory: "Minecraft Forge server"
 | 
				
			||||||
 | 
					  max_heap_size: "2G"
 | 
				
			||||||
		Loading…
	
		Reference in New Issue