def _dir(launcher, im, instance_name): """Print root directory of instance.""" if not instance_name: # TODO print(launcher.get_path(Directory.INSTANCES)) else: instance_name = sanitize_name(instance_name) print(im.get_root(instance_name))
def rename(im, instance_name, new_name): """Rename an instance.""" new_name = sanitize_name(new_name) if im.exists(instance_name): if im.exists(new_name): die("Instance with target name already exists.") im.rename(instance_name, new_name) else: die("No such instance exists.")
def __init__(self, launcher, root, name): self.instance_manager = launcher.instance_manager self.launcher = launcher self.name = sanitize_name(name) self.libraries_root = self.launcher.get_path(Directory.LIBRARIES) self.assets_root = self.launcher.get_path(Directory.ASSETS) self.directory = root self.config = self.launcher.config_manager.get_instance_config( Path("instances", Path(self.name), "config.json"))
def install(pack_id, version, launcher, im, instance_name, use_beta): try: pack_manifest, version_manifest = resolve_pack_meta(pack_id, version, use_beta) except NotImplementedError as ex: die(ex) pack_name = pack_manifest["name"] pack_version = version_manifest["name"] if instance_name is None: instance_name = sanitize_name(f"{pack_name}-{pack_version}") if im.exists(instance_name): die("Instance {} already exists".format(instance_name)) logger.info(f"Installing {pack_name} {pack_version} as {instance_name}") forge_version_name = None game_version = None for target in version_manifest["targets"]: if target["name"] == "forge": try: forge_version_name = forge.install( versions_root=launcher.get_path(Directory.VERSIONS), libraries_root=launcher.get_path(Directory.LIBRARIES), forge_version=target["version"], ) except forge.AlreadyInstalledError as ex: forge_version_name = ex.args[0] elif target["name"] == "minecraft": game_version = target["version"] else: logger.warn(f"Skipping unsupported target {target['name']}") inst_version = forge_version_name or game_version inst = im.create(instance_name, inst_version) inst.config["java.memory.max"] = str(version_manifest["specs"]["recommended"]) + "M" mcdir: Path = inst.get_minecraft_dir() dq = DownloadQueue() for f in version_manifest["files"]: filepath: Path = mcdir / PurePath(f["path"]) / f["name"] filepath.parent.mkdir(exist_ok=True, parents=True) dq.add(f["url"], filepath, f["size"]) logger.info("Downloading modpack files") dq.download() logger.info(f"Installed successfully as {instance_name}")
def install_from_zip(zipfileobj, launcher, instance_manager, instance_name=None): with ZipFile(zipfileobj) as pack_zf: for fileinfo in pack_zf.infolist(): fpath = PurePath(fileinfo.filename) if fpath.parts[-1] == "manifest.json" and len(fpath.parts) <= 2: manifest_zipinfo = fileinfo archive_prefix = fpath.parent break else: raise ValueError("Zip file does not contain manifest") with pack_zf.open(manifest_zipinfo) as fd: manifest = json.load(fd) assert manifest["manifestType"] == "minecraftModpack" assert manifest["manifestVersion"] == 1 assert len(manifest["minecraft"]["modLoaders"]) == 1 forge_ver = manifest["minecraft"]["modLoaders"][0]["id"] assert forge_ver.startswith(FORGE_PREFIX) forge_ver = forge_ver[len(FORGE_PREFIX):] packname = manifest["name"] packver = manifest["version"] if instance_name is None: instance_name = "{}-{}".format(sanitize_name(packname), sanitize_name(packver)) logger.info(f"Installing {packname} version {packver}") else: logger.info( f"Installing {packname} version {packver} as instance {instance_name}" ) if instance_manager.exists(instance_name): die("Instace {} already exists".format(instance_name)) try: forge.install( versions_root=launcher.get_path(Directory.VERSIONS), libraries_root=launcher.get_path(Directory.LIBRARIES), forge_version=forge_ver, ) except forge.AlreadyInstalledError: pass # Trusting the game version from the manifest may be a bad idea inst = instance_manager.create( instance_name, "{}-forge-{}".format(manifest["minecraft"]["version"], forge_ver), ) # This is a random guess, but better than the vanilla 1G inst.config["java.memory.max"] = "4G" project_files = { mod["projectID"]: mod["fileID"] for mod in manifest["files"] } headers = {"User-Agent": "curl"} dq = DownloadQueue() logger.info("Retrieving mod metadata from curse") modcount = len(project_files) mcdir: Path = inst.get_minecraft_dir() moddir = mcdir / "mods" with tqdm(total=modcount) as tq: # Try to get as many file_infos as we can in one request # This endpoint only provides a few "latest" files for each project, # so it's not guaranteed that the response will contain the fileID # we are looking for. It's a gamble, but usually worth it in terms # of request count. The time benefit is not that great, as the endpoint # is slow. resp = requests.post(ADDON_URL, json=list(project_files.keys()), headers=headers) resp.raise_for_status() projects_meta = resp.json() for proj in projects_meta: proj_id = proj["id"] want_file = project_files[proj_id] for file_info in proj["latestFiles"]: if want_file == file_info["id"]: dq.add( file_info["downloadUrl"], moddir / file_info["fileName"], size=file_info["fileLength"], ) del project_files[proj_id] batch_recvd = modcount - len(project_files) logger.debug("Got {} batched".format(batch_recvd)) tq.update(batch_recvd) with ThreadPoolExecutor(max_workers=16) as tpe: def dl(pid, fid): resp = requests.get(GETINFO_URL.format(pid, fid), headers=headers) resp.raise_for_status() file_info = resp.json() assert file_info["id"] == fid dq.add( file_info["downloadUrl"], moddir / file_info["fileName"], size=file_info["fileLength"], ) # Get remaining individually futmap = {} for pid, fid in project_files.items(): fut = tpe.submit(dl, pid, fid) futmap[fut] = (pid, fid) for fut in concurrent.futures.as_completed(futmap.keys()): try: fut.result() except Exception as ex: pid, fid = futmap[fut] logger.error( "Could not get metadata for {}/{}: {}".format( pid, fid, ex)) else: tq.update(1) logger.info("Downloading mod jars") dq.download() logger.info("Copying overrides") overrides = archive_prefix / manifest["overrides"] for fileinfo in pack_zf.infolist(): if fileinfo.is_dir(): continue fname = fileinfo.filename try: outpath = mcdir / PurePath(fname).relative_to(overrides) except ValueError: continue if not outpath.parent.exists(): outpath.parent.mkdir(parents=True, exist_ok=True) with pack_zf.open(fileinfo) as infile, open(outpath, "wb") as outfile: shutil.copyfileobj(infile, outfile) logger.info("Done installing {}".format(instance_name))
def inner(*args, instance_name, **kwargs): return fn(*args, instance_name=sanitize_name(instance_name), **kwargs)