org.jackhuang.hmcl.core.version.MinecraftVersionManager.java Source code

Java tutorial

Introduction

Here is the source code for org.jackhuang.hmcl.core.version.MinecraftVersionManager.java

Source

/*
 * Hello Minecraft! Launcher.
 * Copyright (C) 2013  huangyuhui <huanghongxun2008@126.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see {http://www.gnu.org/licenses/}.
 */
package org.jackhuang.hmcl.core.version;

import org.jackhuang.hmcl.api.game.Extract;
import org.jackhuang.hmcl.api.game.IMinecraftLibrary;
import org.jackhuang.hmcl.api.game.DecompressLibraryJob;
import com.google.gson.JsonSyntaxException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.TreeMap;
import org.jackhuang.hmcl.api.HMCLApi;
import org.jackhuang.hmcl.api.event.version.LoadedOneVersionEvent;
import org.jackhuang.hmcl.api.event.version.RefreshedVersionsEvent;
import org.jackhuang.hmcl.api.event.version.RefreshingVersionsEvent;
import org.jackhuang.hmcl.util.C;
import org.jackhuang.hmcl.api.HMCLog;
import org.jackhuang.hmcl.core.GameException;
import org.jackhuang.hmcl.core.service.IMinecraftProvider;
import org.jackhuang.hmcl.core.service.IMinecraftService;
import org.jackhuang.hmcl.util.sys.FileUtils;
import org.jackhuang.hmcl.core.MCUtils;
import org.jackhuang.hmcl.util.task.TaskWindow;
import org.jackhuang.hmcl.util.ui.MessageBox;
import org.jackhuang.hmcl.util.StrUtils;
import org.jackhuang.hmcl.api.func.Consumer;
import org.jackhuang.hmcl.api.func.Predicate;
import org.jackhuang.hmcl.util.sys.IOUtils;
import org.jackhuang.hmcl.util.ui.SwingUtils;

/**
 *
 * @author huangyuhui
 */
public class MinecraftVersionManager<T extends IMinecraftService> extends IMinecraftProvider<T> {

    final Map<String, MinecraftVersion> versions = new TreeMap<>();

    /**
     *
     * @param p
     */
    public MinecraftVersionManager(T p) {
        super(p);
    }

    @Override
    public Collection<MinecraftVersion> getVersions() {
        return versions.values();
    }

    @Override
    public int getVersionCount() {
        return versions.size();
    }

    @Override
    public synchronized void refreshVersions() {
        HMCLApi.EVENT_BUS.fireChannel(new RefreshingVersionsEvent(this));

        try {
            MCUtils.tryWriteProfile(baseDirectory());
        } catch (IOException ex) {
            HMCLog.warn("Failed to create launcher_profiles.json, Forge/LiteLoader installer will not work.", ex);
        }

        versions.clear();
        File oldDir = new File(baseDirectory(), "bin");
        if (oldDir.exists()) {
            MinecraftClassicVersion v = new MinecraftClassicVersion();
            versions.put(v.id, v);
        }

        File version = new File(baseDirectory(), "versions");
        File[] files = version.listFiles();
        if (files != null && files.length > 0)
            for (File dir : files) {
                String id = dir.getName();
                File jsonFile = new File(dir, id + ".json");

                if (!dir.isDirectory())
                    continue;
                boolean ask = false;
                File[] jsons = null;
                if (!jsonFile.exists()) {
                    jsons = FileUtils.searchSuffix(dir, "json");
                    if (jsons.length == 1)
                        ask = true;
                }
                if (ask) {
                    HMCLog.warn("Found not matched filenames version: " + id + ", json: " + jsons[0].getName());
                    if (MessageBox.show(
                            String.format(C.i18n("launcher.versions_json_not_matched"), id, jsons[0].getName()),
                            MessageBox.YES_NO_OPTION) == MessageBox.YES_OPTION)
                        if (!jsons[0].renameTo(jsonFile))
                            HMCLog.warn("Failed to rename version json " + jsons[0]);
                }
                if (!jsonFile.exists()) {
                    if (MessageBox.show(C.i18n("launcher.versions_json_not_matched_cannot_auto_completion", id),
                            MessageBox.YES_NO_OPTION) == MessageBox.YES_OPTION)
                        FileUtils.deleteDirectoryQuietly(dir);
                    continue;
                }
                MinecraftVersion mcVersion;
                try {
                    mcVersion = readJson(jsonFile);
                    if (mcVersion == null)
                        throw new JsonSyntaxException("Wrong json format, got null.");
                } catch (JsonSyntaxException | IOException e) {
                    HMCLog.warn("Found wrong format json, try to fix it.", e);
                    if (MessageBox.show(C.i18n("launcher.versions_json_not_formatted", id),
                            MessageBox.YES_NO_OPTION) == MessageBox.YES_OPTION) {
                        TaskWindow.factory().execute(service.download().downloadMinecraftVersionJson(id));
                        try {
                            mcVersion = readJson(jsonFile);
                            if (mcVersion == null)
                                throw new JsonSyntaxException("Wrong json format, got null.");
                        } catch (IOException | JsonSyntaxException ex) {
                            HMCLog.warn("Ignoring: " + dir + ", the json of this Minecraft is malformed.", ex);
                            continue;
                        }
                    } else
                        continue;
                }
                try {
                    if (!id.equals(mcVersion.id)) {
                        HMCLog.warn("Found: " + dir + ", it contains id: " + mcVersion.id + ", expected: " + id
                                + ", this app will fix this problem.");
                        mcVersion.id = id;
                        FileUtils.writeQuietly(jsonFile, C.GSON.toJson(mcVersion));
                    }

                    versions.put(id, mcVersion);
                    HMCLApi.EVENT_BUS.fireChannel(new LoadedOneVersionEvent(this, id));
                } catch (Exception e) {
                    HMCLog.warn("Ignoring: " + dir + ", the json of this Minecraft is malformed.", e);
                }
            }
        HMCLApi.EVENT_BUS.fireChannel(new RefreshedVersionsEvent(this));
    }

    @Override
    public File versionRoot(String id) {
        return new File(baseDirectory(), "versions/" + id);
    }

    @Override
    public boolean removeVersionFromDisk(String name) {
        File version = versionRoot(name);
        if (!version.exists())
            return true;

        versions.remove(name);
        return FileUtils.deleteDirectoryQuietly(version);
    }

    /**
     * 
     * @param id version id
     * @return null if json syntax is wrong or cannot read the json file.
     */
    public MinecraftVersion readJson(String id) {
        try {
            return readJson(new File(versionRoot(id), id + ".json"));
        } catch (IOException | JsonSyntaxException e) {
            return null;
        }
    }

    public MinecraftVersion readJson(File file) throws IOException {
        return C.GSON.fromJson(FileUtils.read(file, IOUtils.DEFAULT_CHARSET), MinecraftVersion.class);
    }

    @Override
    public boolean renameVersion(String from, String to) {
        try {
            File toDir = versionRoot(to);
            if (!versionRoot(from).renameTo(toDir))
                return false;
            File toJson = new File(toDir, to + ".json");
            File toJar = new File(toDir, to + ".jar");
            if (!new File(toDir, from + ".json").renameTo(toJson))
                HMCLog.warn("MinecraftVersionManager.RenameVersion: Failed to rename json");
            MinecraftVersion mcVersion = readJson(toJson);
            mcVersion.id = to;
            FileUtils.writeQuietly(toJson, C.GSON.toJson(mcVersion));
            File oldJar = new File(toDir, from + ".jar");
            if (oldJar.exists() && !oldJar.renameTo(toJar))
                HMCLog.warn("Failed to rename pre jar " + oldJar + " to new jar " + toJar);
            return true;
        } catch (IOException | JsonSyntaxException e) {
            HMCLog.warn("Failed to rename " + from + " to " + to + ", the json of this Minecraft is malformed.", e);
            return false;
        }
    }

    @Override
    public File getRunDirectory(String id) {
        if (getVersionById(id) != null)
            if ("version".equals(getVersionById(id).runDir))
                return versionRoot(id);
        return baseDirectory();
    }

    @Override
    public boolean install(String id, Consumer<MinecraftVersion> callback) {
        if (!TaskWindow.factory().append(service.download().downloadMinecraft(id)).execute())
            return false;
        if (callback != null) {
            File mvt = new File(versionRoot(id), id + ".json");
            MinecraftVersion v = readJson(id);
            if (v == null)
                return false;
            callback.accept(v);
            FileUtils.writeQuietly(mvt, C.GSON.toJson(v));
        }
        refreshVersions();
        return true;
    }

    @Override
    public void open(String mv, String name) {
        SwingUtils.openFolder((name == null) ? getRunDirectory(mv) : new File(getRunDirectory(mv), name));
    }

    @Override
    public File getLibraryFile(MinecraftVersion version, IMinecraftLibrary lib) {
        return lib.getFilePath(baseDirectory());
    }

    @Override
    public DecompressLibraryJob getDecompressLibraries(MinecraftVersion v) throws GameException {
        if (v.libraries == null)
            throw new GameException("Wrong format: minecraft.json");
        ArrayList<File> unzippings = new ArrayList<>();
        ArrayList<Extract> extractRules = new ArrayList<>();
        for (IMinecraftLibrary l : v.libraries) {
            final File f = getLibraryFile(v, l);
            if (l.isNative() && v.isAllowedToUnpackNatives() && l.allow() && f != null) {
                unzippings.add(f);
                extractRules.add(l.getDecompressExtractRules());
            }
        }
        return new DecompressLibraryJob(unzippings.toArray(new File[unzippings.size()]),
                extractRules.toArray(new Extract[extractRules.size()]), getDecompressNativesToLocation(v));
    }

    @Override
    public File getDecompressNativesToLocation(MinecraftVersion v) {
        return v == null ? null : v.getNatives(baseDirectory());
    }

    @Override
    public File getMinecraftJar(String id) {
        if (versions.containsKey(id))
            return versions.get(id).getJar(baseDirectory());
        else
            return null;
    }

    @Override
    public MinecraftVersion getOneVersion(Predicate<MinecraftVersion> pred) {
        for (MinecraftVersion v : versions.values())
            if (pred == null || pred.apply(v))
                return v;
        return null;
    }

    @Override
    public MinecraftVersion getVersionById(String id) {
        return StrUtils.isBlank(id) ? null : versions.get(id);
    }

    @Override
    public boolean onLaunch(String id) {
        // Fix bug in Minecraft 1.8
        File resourcePacks = new File(getRunDirectory(id), "resourcepacks");
        if (!FileUtils.makeDirectory(resourcePacks))
            HMCLog.warn("Failed to make resourcePacks: " + resourcePacks);
        return true;
    }

    @Override
    public void cleanFolder() {
        for (MinecraftVersion s : getVersions()) {
            FileUtils.deleteDirectoryQuietly(new File(versionRoot(s.id), s.id + "-natives"));
            File f = getRunDirectory(s.id);
            String[] dir = { "natives", "native", "$native", "AMD", "crash-reports", "logs", "asm", "NVIDIA",
                    "server-resource-packs", "natives", "native" };
            for (String str : dir)
                FileUtils.deleteDirectoryQuietly(new File(f, str));
            String[] files = { "output-client.log", "usercache.json", "usernamecache.json", "hmclmc.log" };
            for (String str : files)
                if (!new File(f, str).delete())
                    HMCLog.warn("Failed to delete " + str);
        }
    }

    @Override
    public void initializeMinecraft() {
    }
}