import zipfile import json import sys import logging import minecraft_launcher_lib from pathlib import Path # action plan for final product: # 1) Get a list of mod jars from a directory # 2) Install appropriate version of minecraft if it is not already installed # 3) Install appropriate version of minecraft forge if it is not already installed # 4) Launch empty version of minecraft forge to generate boilerplate file structure # 5) Exit the process after it launches successfully # 6) For each Jar: # a) Copy jar to directory # b) Attempt to launch the game # c) Record whether or not the game successfully launched/built/etc # d) If the game failed to launch, mark the jar as disabled # e) Continue to next jar class MinecraftMod: def __init__(self, fileName, filePath, modid, parentMods=None): self.parentMods = parentMods or [] self.fileName = fileName self.filePath = filePath self.modid = modid def get_mod_info(target_file: Path): with zipfile.ZipFile(target_file) as z: info_files = [f for f in z.filelist if not f.is_dir() and '.info' in f.filename.lower()] rtn_json = json.loads(z.read(info_files[0]))[0] rtn_json['path'] = target_file return MinecraftMod( fileName=z.filename, filePath=z.filename, modid=rtn_json['modid'], parentMods=rtn_json.get('dependencies', []) ) def get_modpack_info(target_dir: Path): for f in target_dir.glob('*.jar'): try: yield get_mod_info(f) except (KeyError, IndexError) as e: logging.warning(f'There is no .info in the file {f.name}!') logging.debug(f"{e}") except json.decoder.JSONDecodeError as e: logging.warning(f"The file {f.name} has a corrupted or malformed .info file - skipping!") except BaseException as e: logging.fatal(f"While parsing file {f.name}, encountered the following unhandled error: {e}") raise e def get_forge_version(minecraft_version: str): return minecraft_launcher_lib.forge.find_forge_version(minecraft_version) # potentially unnecessary, could substitue with run_forge_installer(version) instead of doing it all in the background? def install_forge_for_version(minecraft_version: str): minecraft_launcher_lib.forge.install_forge_version( get_forge_version(minecraft_version), path=minecraft_launcher_lib.utils.get_minecraft_directory() ) def launch_minecraft(): # see https://pypi.org/project/minecraft-launcher-lib/ # We now have a way to automatically install and launch minecraft forge versions via python acct_resp = minecraft_launcher_lib.account.login_user( input("Enter your minecraft username"), input("Enter your minecraft password") ) options = { # This is needed "username": acct_resp['selectedProfile']['name'], "uuid": acct_resp['selectedProfile']['id'], "token": acct_resp['accessToken'], # This is optional "executablePath": "java", # The path to the java executable "jvmArguments": [], # The jvmArguments "launcherName": "minecraft-launcher-lib", # The name of your launcher "launcherVersion": "1.0", # The version of your launcher "gameDirectory": r"C:\Users\VY Canis Majoris\AppData\Roaming\.moddedminecraft\1.12\1.12.2\test", # The gameDirectory (default is the path given in arguments) "demo": False, # Run Minecraft in demo mode "customResolution": False, # Enable custom resolution "resolutionWidth": "854", # The resolution width "resolutionHeight": "480", # The resolution heigth # "server": "example.com", # The ip of a server where Minecraft connect to after start # "port": "123", # The port of a server where Minecraft connect to after start # "nativesDirectory": "minecraft_directory/versions/version/natives" # The natives directory # "enableLoggingConfig": False, # Enable use of the log4j configuration file } def main(directory=Path('.')): modpack_info = list(get_modpack_info(directory)) root_mods = [mp for mp in modpack_info if not mp.parentMods] dependant_mods = [mp for mp in modpack_info if mp.parentMods] mod_tree = [] for root_mod in root_mods: mod_tree.append({ root_mod.modid: { 'depends_on': [mod.modid for mod in dependant_mods if root_mod.modid in mod.parentMods] } }) print(json.dumps(mod_tree, indent=4)) if __name__ == "__main__": args = {arg.lower(): val for arg, val in (a[2:].split('=') for a in sys.argv if '--' in a.lower())} logging.getLogger().setLevel(logging.DEBUG) main(Path(r"C:\Users\VY Canis Majoris\AppData\Roaming\.moddedminecraft\1.12\1.12.2\Sinkhole\mods"))