コード例 #1
0
def setdefault(am, account):
    """Set the account as default."""
    try:
        default = am.get(account)
        am.set_default(default)
    except AccountError as e:
        logger.error("Could not set default account: %s", e)
コード例 #2
0
def assert_java(java, wanted):
    try:
        jinfo = get_java_info(java)
        bitness = jinfo.get("sun.arch.data.model", None)
        if bitness and bitness != "64":
            logger.warning(
                "You are not using 64-bit java. Things will probably not work."
            )

        logger.info("Using java version: {} ({})".format(
            jinfo["java.version"], jinfo["java.vm.name"]))

        if not check_version_against(jinfo["java.version"], wanted):
            logger.warning("The version of Minecraft you are launching "
                           "uses java {} by default.".format(
                               wanted_to_str(wanted)))

            logger.warning(
                "You may experience issues, especially with older versions of Minecraft."
            )

            major = get_major_version(jinfo["java.version"])
            if int(major) < wanted["majorVersion"]:
                logger.error(
                    "Note that at least java {} is required to launch at all.".
                    format(wanted_to_str(wanted)))

        return jinfo

    except FileNotFoundError:
        die("Could not execute java at: {}. Have you installed it? Is it in yout PATH?"
            .format(java))
コード例 #3
0
 def download_libraries(self, java_info, verify_hashes=False, force=False):
     """Downloads missing libraries."""
     logger.info("Checking libraries.")
     q = DownloadQueue()
     for library in self.get_libraries(java_info):
         if not library.available:
             continue
         basedir = self.launcher.get_path(Directory.LIBRARIES)
         abspath = library.get_abspath(basedir)
         ok = abspath.is_file() and os.path.getsize(abspath) > 0
         if verify_hashes and library.sha1 is not None:
             ok = ok and file_sha1(abspath) == library.sha1
         if not ok and not library.url:
             logger.error(
                 f"Library {library.filename} is missing or corrupt "
                 "and has no download url.")
             continue
         if force or not ok:
             q.add(library.url, library.get_abspath(basedir), library.size)
     jardl = self.get_jarfile_dl(verify_hashes, force)
     if jardl is not None:
         url, size = jardl
         q.add(url, self.jarfile, size=size)
     if len(q) > 0:
         logger.info("Downloading {} libraries.".format(len(q)))
     if not q.download():
         logger.error(
             "Some libraries failed to download. If they are part of a non-vanilla "
             "profile, the original installer may need to be used.")
コード例 #4
0
def refresh(am, account):
    """Refresh access token with Mojang servers."""
    try:
        a = am.get(account)
        a.refresh()
    except (AccountError, RefreshError) as e:
        logger.error("Could not refresh account: %s", e)
コード例 #5
0
    def download(self):
        logger.debug("Downloading {} files.".format(self.total))
        disable_progressbar = picomc.logging.debug

        if self.known_size:
            cm_progressbar = tqdm(
                total=self.total_size,
                disable=disable_progressbar,
                unit_divisor=1024,
                unit="iB",
                unit_scale=True,
            )
        else:
            cm_progressbar = tqdm(total=self.total, disable=disable_progressbar)

        with cm_progressbar as tq, ThreadPoolExecutor(max_workers=self.workers) as tpe:
            for i, (url, dest) in enumerate(self.queue, start=1):
                cb = tq.update if self.known_size else (lambda x: None)
                fut = tpe.submit(self.download_file, i, url, dest, cb)
                self.fut_to_url[fut] = url

            try:
                for fut in concurrent.futures.as_completed(self.fut_to_url.keys()):
                    self.reap_future(fut, tq)
            except KeyboardInterrupt as ex:
                self.cancel(tq, tpe)
                raise ex from None

        # Do this at the end in order to not break the progress bar.
        for error in self.errors:
            logger.error(error)

        return not self.errors
コード例 #6
0
def version_cli(forge_version, game, latest):
    """Resolve version without installing."""
    try:
        game_version, forge_version, version = resolve_version(
            game, forge_version, latest)
        logger.info(
            f"Found Forge version {forge_version} for Minecraft {game_version}"
        )
    except VersionResolutionError as e:
        logger.error(e)
コード例 #7
0
def launch(am, im, instance_name, account, version_override, verify):
    """Launch the instance."""
    if account is None:
        account = am.get_default()
    else:
        account = am.get(account)
    if not im.exists(instance_name):
        logger.error("No such instance exists.")
        return
    inst = im.get(instance_name)
    try:
        inst.launch(account, version_override, verify_hashes=verify)
    except AccountError as e:
        logger.error("Not launching due to account error: {}".format(e))
コード例 #8
0
 def subproc(obj):
     args = []
     for a in obj:
         if isinstance(a, str):
             args.append(a)
         else:
             if "rules" in a and not match_ruleset(a["rules"], java_info):
                 continue
             if isinstance(a["value"], list):
                 args.extend(a["value"])
             elif isinstance(a["value"], str):
                 args.append(a["value"])
             else:
                 logger.error("Unknown type of value field.")
     return args
コード例 #9
0
def create(am, account, mojang_username, microsoft):
    """Create an account."""
    try:
        if mojang_username:
            if microsoft:
                logger.error(
                    "Do not use --microsoft with mojang_username argument")
                return
            acc = OnlineAccount.new(am, account, mojang_username)
        elif microsoft:
            acc = MicrosoftAccount.new(am, account)
        else:
            acc = OfflineAccount.new(am, account)
        am.add(acc)
    except AccountError as e:
        logger.error("Could not create account: %s", e)
コード例 #10
0
ファイル: account.py プロジェクト: Zajozor/picomc
 def refresh(self, force=False):
     if self.fresh and not force:
         return False
     if self.is_authenticated:
         if self.validate():
             return
         else:
             try:
                 refresh = self._am.yggdrasil.refresh(self.access_token)
                 self.access_token, self.uuid, self.gname = refresh
                 self.fresh = True
                 return True
             except RefreshError as e:
                 logger.error(
                     "Failed to refresh access_token," " please authenticate again."
                 )
                 self.is_authenticated = False
                 raise e
             finally:
                 self.save()
     else:
         raise AccountError("Not authenticated.")
コード例 #11
0
def install_cli(launcher, name, forge_version, game, latest):
    """Installs Forge.

    The best version is selected automatically based on the given parameters.
    By default, only stable Forge versions are considered, use --latest to
    enable beta versions as well.

    You can install a specific version of forge using the FORGE_VERSION argument.
    You can also choose the newest version for a specific version of Minecraft
    using --game."""
    try:
        install(
            launcher.get_path(Directory.VERSIONS),
            launcher.get_path(Directory.LIBRARIES),
            game,
            forge_version,
            latest,
            version_name=name,
        )
    except (VersionResolutionError, InstallationError,
            AlreadyInstalledError) as e:
        logger.error(e)
コード例 #12
0
def authenticate(am, account):
    """Retrieve access token from Mojang servers using password."""

    try:
        a = am.get(account)
    except AccountError:
        logger.error("AccountError", exc_info=True)
        return

    try:
        if isinstance(a, OfflineAccount):
            logger.error("Offline accounts cannot be authenticated")
        elif isinstance(a, OnlineAccount):
            import getpass

            p = getpass.getpass("Password: "******"Unknown account type")
    except AuthenticationError as e:
        logger.error("Authentication failed: %s", e)
コード例 #13
0
def create(im, instance_name, version):
    """Create a new instance."""
    if im.exists(instance_name):
        logger.error("An instance with that name already exists.")
        return
    im.create(instance_name, version)
コード例 #14
0
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))
コード例 #15
0
def die(mesg, code=1):
    logger.error(mesg)
    sys.exit(code)
コード例 #16
0
def delete(im, instance_name):
    """Delete the instance (from disk)."""
    if im.exists(instance_name):
        im.delete(instance_name)
    else:
        logger.error("No such instance exists.")
コード例 #17
0
def remove(am, account):
    """Remove the account."""
    try:
        am.remove(account)
    except AccountError as e:
        logger.error("Could not remove account: %s", e)
コード例 #18
0
    def _exec_mc(self, account, v, java, java_info, gamedir, libraries,
                 natives, verify_hashes):
        libs = [lib.get_abspath(self.libraries_root) for lib in libraries]
        libs.append(v.jarfile)
        classpath = join_classpath(*libs)

        version_type, user_type = (("picomc", "mojang") if account.online else
                                   ("picomc/offline", "offline"))

        mc = v.vspec.mainClass

        if hasattr(v.vspec, "minecraftArguments"):
            mcargs = shlex.split(v.vspec.minecraftArguments)
            sjvmargs = [
                "-Djava.library.path={}".format(natives), "-cp", classpath
            ]
        elif hasattr(v.vspec, "arguments"):
            mcargs, jvmargs = process_arguments(v.vspec.arguments, java_info)
            sjvmargs = []
            for a in jvmargs:
                tmpl = Template(a)
                res = tmpl.substitute(
                    natives_directory=natives,
                    launcher_name="picomc",
                    launcher_version=picomc.__version__,
                    classpath=classpath,
                    version_name=v.version_name,
                    jar_name=v.jarname,
                    library_directory=self.libraries_root,
                    classpath_separator=os.pathsep,
                )
                sjvmargs.append(res)

        if not account.can_launch_game():
            logger.error(
                "Account is not ready to launch game. Online accounts need to be authenticated at least once"
            )
            return
        try:
            account.refresh()
        except RefreshError as e:
            logger.warning(f"Failed to refresh account due to an error: {e}")

        smcargs = []
        for a in mcargs:
            tmpl = Template(a)
            res = tmpl.substitute(
                auth_player_name=account.gname,
                auth_uuid=account.uuid,
                auth_access_token=account.access_token,
                # Only used in old versions.
                auth_session="token:{}:{}".format(account.access_token,
                                                  account.uuid),
                user_type=user_type,
                user_properties={},
                version_type=version_type,
                version_name=v.version_name,
                game_directory=gamedir,
                assets_root=self.assets_root,
                assets_index_name=v.vspec.assets,
                game_assets=v.get_virtual_asset_path(),
                clientid="",  # TODO fill these out properly
                auth_xuid="",
            )
            smcargs.append(res)

        my_jvm_args = [
            "-Xms{}".format(self.config["java.memory.min"]),
            "-Xmx{}".format(self.config["java.memory.max"]),
        ]

        if verify_hashes:
            my_jvm_args.append("-Dpicomc.verify=true")

        my_jvm_args += shlex.split(self.config["java.jvmargs"])

        fargs = [java] + sjvmargs + my_jvm_args + [mc] + smcargs
        if logging.debug:
            logger.debug("Launching: " + shlex.join(fargs))
        else:
            logger.info("Launching the game")
        subprocess.run(fargs, cwd=gamedir)