Package com.atlauncher.data

Source Code of com.atlauncher.data.Instance

/*
* ATLauncher - https://github.com/ATLauncher/ATLauncher
* Copyright (C) 2013 ATLauncher
*
* 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 com.atlauncher.data;

import com.atlauncher.App;
import com.atlauncher.Gsons;
import com.atlauncher.LogManager;
import com.atlauncher.data.mojang.auth.AuthenticationResponse;
import com.atlauncher.data.openmods.OpenEyeReportResponse;
import com.atlauncher.gui.dialogs.ProgressDialog;
import com.atlauncher.mclauncher.LegacyMCLauncher;
import com.atlauncher.mclauncher.MCLauncher;
import com.atlauncher.utils.Authentication;
import com.atlauncher.utils.Utils;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import java.awt.BorderLayout;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* This class handles contains information about a single Instance in the Launcher. An Instance being an installed
* version of a ModPack separate to others by file structure.
*/
public class Instance implements Cloneable {
    /**
     * The name of the Instance.
     */
    private String name;

    /**
     * The name of the Pack this instance is for.
     */
    private String pack;

    /**
     * The username of the user who installed this if it's set to be for that user only.
     */
    private String installedBy;

    /**
     * The version installed for this Instance.
     */
    private String version;

    /**
     * The hash of this instance if it's a dev version.
     */
    private String hash;

    /**
     * The version of Minecraft that this Instance uses.
     */
    private String minecraftVersion;

    /**
     * The minimum RAM/memory recommended for this Instance by the pack developer/s.
     */
    private int memory = 0;

    /**
     * The minimum PermGen/MetaSpace recommended for this Instance by the pack developer/s.
     */
    private int permgen = 0;

    /**
     * Comma separated list of the order of Jar's to be added to the class path when launching Minecraft.
     */
    private String jarOrder;

    /**
     * Comma seperated list of the libraries needed by Minecraft/Forge to be added to the class path when launching
     * Minecraft.
     */
    private String librariesNeeded = null;

    /**
     * The extra arguments to be added to the command when launching Minecraft. Generally involves things such as the
     * tweakClass/s for Forge.
     */
    private String extraArguments = null;

    /**
     * The arguments required by Minecraft to be added to the command when launching Minecraft. Generally involves thing
     * such as handling of authentication, assets paths etc.
     */
    private String minecraftArguments = null;

    /**
     * The main class to be run when launching Minecraft.
     */
    private String mainClass = null;

    /**
     * The version of assets used by this Minecraft instance.
     */
    private String assets = null;

    /**
     * If this instance has been converted or not from the old format.
     */
    private boolean isConverted = false;

    /**
     * The Pack object for the pack this Instance was installed from. This is not stored in the instances instance.json
     * file as Pack's can be deleted from the system.
     *
     * @see com.atlauncher.data.Pack
     */
    private transient Pack realPack;

    /**
     * If this Instance was installed from a development version of the Pack.
     */
    private boolean isDev;

    /**
     * If this Instance is playable or not. It may become unplayable after a failed update or if files are found
     * corrupt.
     */
    private boolean isPlayable;

    /**
     * If this instance uses the MCLauncher or the LegacyMCLauncher class to load Minecraft.
     *
     * @see com.atlauncher.mclauncher.MCLauncher
     * @see com.atlauncher.mclauncher.LegacyMCLauncher
     */
    private boolean newLaunchMethod;

    /**
     * List of DisableableMod objects for the mods in the Instance.
     *
     * @see com.atlauncher.data.DisableableMod
     */
    private List<DisableableMod> mods;

    /**
     * List of versions of the Pack this instance comes from that the user has said to not be reminded about updating
     * to.
     */
    private List<String> ignoredUpdates;

    /**
     * Instantiates a new instance.
     *
     * @param name               the name of the Instance
     * @param pack               the name of the Pack this Instance is of
     * @param realPack           the Pack object for the Pack this Instance is of
     * @param installJustForMe   if this instance is only meant to be used by the original installer
     * @param version            the version of the Pack this Instance is of
     * @param minecraftVersion   the Minecraft version this Instance runs off
     * @param memory             the minimum RAM/memory as recommended by the pack developer/s
     * @param permgen            the minimum PermGen/Metaspace as recommended by the pack developer/s
     * @param mods               the mods installed in this Instance
     * @param jarOrder           the order that jar mods are loaded into the class path
     * @param librariesNeeded    the libraries needed to launch Minecraft
     * @param extraArguments     the extra arguments for launching the pack
     * @param minecraftArguments the arguments needed by Minecraft to run
     * @param mainClass          the main class to run when launching Minecraft
     * @param assets             the assets version being used by Minecraft
     * @param isDev              if this Instance is using a dev version of the pack
     * @param isPlayable         if this instance is playable
     * @param newLaunchMethod    if this instance is using the new launch method for Minecraft
     */
    public Instance(String name, String pack, Pack realPack, boolean installJustForMe, String version, String
            minecraftVersion, int memory, int permgen, List<DisableableMod> mods, String jarOrder, String
            librariesNeeded, String extraArguments, String minecraftArguments, String mainClass, String assets,
                    boolean isDev, boolean isPlayable, boolean newLaunchMethod) {
        this.name = name;
        this.pack = pack;
        this.realPack = realPack;
        this.version = version;
        this.minecraftVersion = minecraftVersion;
        this.memory = memory;
        this.permgen = permgen;
        this.mods = mods;
        this.jarOrder = jarOrder;
        this.librariesNeeded = librariesNeeded;
        this.mainClass = mainClass;
        this.assets = assets;
        this.jarOrder = jarOrder;
        this.extraArguments = extraArguments;
        this.minecraftArguments = minecraftArguments;
        this.isDev = isDev;
        this.isPlayable = isPlayable;
        this.newLaunchMethod = newLaunchMethod;
        if (installJustForMe) {
            this.installedBy = App.settings.getAccount().getMinecraftUsername();
        } else {
            this.installedBy = null;
        }
        this.isConverted = true;
    }

    /**
     * Instantiates a new instance with it defaulting to being playable.
     *
     * @param name               the name of the Instance
     * @param pack               the name of the Pack this Instance is of
     * @param realPack           the Pack object for the Pack this Instance is of
     * @param installJustForMe   if this instance is only meant to be used by the original installer
     * @param version            the version of the Pack this Instance is of
     * @param minecraftVersion   the Minecraft version this Instance runs off
     * @param memory             the minimum RAM/memory as recommended by the pack developer/s
     * @param permgen            the minimum PermGen/Metaspace as recommended by the pack developer/s
     * @param mods               the mods installed in this Instance
     * @param jarOrder           the order that jar mods are loaded into the class path
     * @param librariesNeeded    the libraries needed to launch Minecraft
     * @param extraArguments     the extra arguments for launching the pack
     * @param minecraftArguments the arguments needed by Minecraft to run
     * @param mainClass          the main class to run when launching Minecraft
     * @param assets             the assets version being used by Minecraft
     * @param isDev              if this Instance is using a dev version of the pack
     * @param newLaunchMethod    if this instance is using the new launch method for Minecraft
     */
    public Instance(String name, String pack, Pack realPack, boolean installJustForMe, String version, String
            minecraftVersion, int memory, int permgen, List<DisableableMod> mods, String jarOrder, String
            librariesNeeded, String extraArguments, String minecraftArguments, String mainClass, String assets,
                    boolean isDev, boolean newLaunchMethod) {
        this(name, pack, realPack, installJustForMe, version, minecraftVersion, memory, permgen, mods, jarOrder,
                librariesNeeded, extraArguments, minecraftArguments, mainClass, assets, isDev, true, newLaunchMethod);
    }

    /**
     * Gets this instances name.
     *
     * @return the instances name
     */
    public String getName() {
        return this.name;
    }

    /**
     * Sets a new name for this Instance. Used primarily when renaming a cloned instance.
     *
     * @param newName the new name for this Instance
     */
    public void setName(String newName) {
        this.name = newName;
    }

    /**
     * Gets the safe name of the Instance used in file paths. Removes all non alphanumeric characters.
     *
     * @return the safe name of the Instance.
     */
    public String getSafeName() {
        return this.name.replaceAll("[^A-Za-z0-9]", "");
    }

    /**
     * Gets the name of the Pack this Instance was created from. Pack's can be deleted/removed in the future.
     *
     * @return the name of the Pack the Instance was created from.
     */
    public String getPackName() {
        return pack;
    }

    /**
     * Checks if the Instance has mods installed.
     *
     * @return true if there are mods installed in the Instance
     */
    public boolean hasInstalledMods() {
        return (this.mods == null ? false : (this.mods.size() >= 1 ? true : false));
    }

    /**
     * Gets the order to load any jar mods into the class path when launching Minecraft.
     *
     * @return comma separated list of filenames to jar mods in their correct loading order
     */
    public String getJarOrder() {
        return this.jarOrder;
    }

    /**
     * Sets the order to load the jars from the jarmods folder.
     *
     * @param jarOrder comma separated list of filenames for the order to load the mods from the jarmods folder
     */
    public void setJarOrder(String jarOrder) {
        this.jarOrder = jarOrder;
    }

    /**
     * Gets the minimum recommended RAM/memory for this Instance based off what the Pack specifies. Defaults to 0 if
     * there is none specified by the pack. Value is in MB.
     *
     * @return the minimum RAM/memory recommended for this Instance in MB
     */
    public int getMemory() {
        return this.memory;
    }

    /**
     * Sets the minimum recommended RAM/memory for this Instance in MB.
     *
     * @param memory the minimum recommended RAM/memory for this Instance in MB
     */
    public void setMemory(int memory) {
        this.memory = memory;
    }

    /**
     * Gets a List of the installed mods in this Instance. Mods are listed as DisableableMod objects.
     *
     * @return a List of DisableableMod objects of the installed mods in this instance or null if none
     */
    public List<DisableableMod> getInstalledMods() {
        return this.mods;
    }

    /**
     * Gets the minimum recommended PermGen/Metaspace size for this Instance based off what the Pack specifies. Defaults
     * to 0 if there is non specified by the pack. Value is in MB.
     *
     * @return the minimum PermGen/Metaspace recommended for this Instance in MB
     */
    public int getPermGen() {
        return this.permgen;
    }

    /**
     * Renames this instance including renaming the folder in the Instances directory to the new name provided.
     *
     * @param newName the new name of the Instance
     * @return true if the Instances folder was renamed and false if it failed
     */
    public boolean rename(String newName) {
        String oldName = this.name;
        File oldDir = getRootDirectory();
        this.name = newName;
        File newDir = getRootDirectory();
        if (oldDir.renameTo(newDir)) {
            return true;
        } else {
            this.name = oldName;
            return false;
        }
    }

    /**
     * Gets the name of the Pack this Instance was created from in a safe manner by removing all non alphanumeric
     * characters which is then safe for use inside file paths and URL's.
     *
     * @return the safe name of the Pack
     */
    public String getSafePackName() {
        return this.pack.replaceAll("[^A-Za-z0-9]", "");
    }

    /**
     * Gets a ImageIcon object for the image file of the Pack for use in displaying in the Packs and Instances tabs.
     *
     * @return ImageIcon for this Instances Pack
     */
    public ImageIcon getImage() {
        File customImage = new File(this.getRootDirectory(), "instance.png");
        File instancesImage = new File(App.settings.getImagesDir(), getSafePackName().toLowerCase() + ".png");

        if (customImage.exists()) {
            try {
                BufferedImage img = ImageIO.read(customImage);
                Image dimg = img.getScaledInstance(300, 150, Image.SCALE_SMOOTH);
                return new ImageIcon(dimg);
            } catch (IOException e) {
                App.settings.logStackTrace("Error creating scaled image from the custom image of instance " + this
                        .getName(), e);
            }
        }

        if (instancesImage.exists()) {
            return Utils.getIconImage(instancesImage);

        } else {
            return Utils.getIconImage(new File(App.settings.getImagesDir(), "defaultimage.png"));
        }
    }

    /**
     * Gets the description of the Pack this Instance was installed from if it's still available in the Launcher. If the
     * pack no longer exists then it simply returns "No Description".
     *
     * @return the description of the Pack this Instance was created from
     */
    public String getPackDescription() {
        if (this.realPack != null) {
            return this.realPack.getDescription();
        } else {
            return Language.INSTANCE.localize("pack.nodescription");
        }
    }

    /**
     * Checks if this Instance has been converted or not from the old arguments storage.
     *
     * @return true if this Instance has already been converted
     */
    public boolean hasBeenConverted() {
        return this.isConverted;
    }

    /**
     * Checks to see if Leaderboards are enabled for the Pack this Instance was created from. If the pack no longer
     * exists we don't allow logging of Leaderboard statistics.
     *
     * @return true if Leaderboard are enabled and statistics can be sent
     */
    public boolean isLeaderboardsEnabled() {
        return (this.realPack != null && this.realPack.isLeaderboardsEnabled());
    }

    /**
     * Checks to see if Logging is enabled for the Pack this Instance was created from. If the pack no longer exists we
     * don't allow logging.
     *
     * @return true if Logging is enabled
     */
    public boolean isLoggingEnabled() {
        return (this.realPack != null && this.realPack.isLoggingEnabled());
    }

    /**
     * This stops the popup informing a user that this Instance has an update when they go to play this Instance. It
     * will simply deny the current version from showing up again informing the user when their Instance is not using
     * the latest version.
     */
    public void ignoreUpdate() {
        if (this.ignoredUpdates == null) {
            this.ignoredUpdates = new ArrayList<String>();
        }
        String version = getLatestVersion();
        if (!hasUpdateBeenIgnored(version)) {
            this.ignoredUpdates.add(version);
            App.settings.saveInstances();
        }
    }

    /**
     * Checks to see if a given version has been ignored from showing update prompts when the Instance is played.
     *
     * @param version the version to check if it's been ignored in the past
     * @return true if the user has chosen to ignore updates for the given version
     */
    public boolean hasUpdateBeenIgnored(String version) {
        if (version == null || ignoredUpdates == null || ignoredUpdates.size() == 0) {
            return false;
        }
        for (String ignoredVersion : ignoredUpdates) {
            if (ignoredVersion.equalsIgnoreCase(version)) {
                return true;
            }
        }
        return false;
    }

    /**
     * This converts an old Instance using old Minecraft argument storage to the new method of storage.
     */
    public void convert() {
        if (this.minecraftArguments != null) {
            // Minecraft arguments are now extraArguments if found
            this.extraArguments = this.minecraftArguments;
            this.minecraftArguments = null;
        }
        this.isConverted = true;
    }

    /**
     * This removes a given DisableableMod object and removes it from the list of installed mods as well as deleting the
     * file.
     *
     * @param mod the DisableableMod object for the mod to remove
     */
    public void removeInstalledMod(DisableableMod mod) {
        Utils.delete((mod.isDisabled() ? mod.getDisabledFile(this) : mod.getFile(this)));
        this.mods.remove(mod); // Remove mod from mod List
    }

    /**
     * Gets the version of the Pack that this Instance is based off.
     *
     * @return the version of the Pack this Instance is based off
     */
    public String getVersion() {
        return this.version;
    }

    /**
     * Sets the version of the Pack this Instance was created from.
     *
     * @param version the version of the Pack this Instance was created from
     */
    public void setVersion(String version) {
        this.version = version;
    }

    /**
     * Gets the Minecraft Version that this Instance uses.
     *
     * @return the Minecraft Version that this Instance uses
     */
    public String getMinecraftVersion() {
        return this.minecraftVersion;
    }

    /**
     * Sets the Minecraft version of the Pack this Instance was created from.
     *
     * @param minecraftVersion the new minecraft version
     */
    public void setMinecraftVersion(String minecraftVersion) {
        this.minecraftVersion = minecraftVersion;
    }

    /**
     * Gets a File object for the root directory of this Instance.
     *
     * @return File object for the root directory of this Instance
     */
    public File getRootDirectory() {
        return new File(App.settings.getInstancesDir(), getSafeName());
    }

    /**
     * Gets a File object for the directory where the assets for this version of Minecraft are stored.
     *
     * @return File object for the assets directory used by Minecraft
     */
    public File getAssetsDir() {
        return new File(App.settings.getVirtualAssetsDir(), getAssets());
    }

    /**
     * Gets a File object for the saves directory of this Instance.
     *
     * @return File object for the saves directory of this Instance
     */
    public File getSavesDirectory() {
        return new File(getRootDirectory(), "saves");
    }

    /**
     * Gets a File object for the reports directory of this Instance where OpenEye stores it's pending crash reports.
     *
     * @return File object for the reports directory of this Instance
     */
    public File getReportsDirectory() {
        return new File(getRootDirectory(), "reports");
    }

    /**
     * Gets a File object for the mods directory of this Instance.
     *
     * @return File object for the mods directory of this Instance
     */
    public File getModsDirectory() {
        return new File(getRootDirectory(), "mods");
    }

    /**
     * Gets a File object for the IC2 library directory of this Instance.
     *
     * @return File object for the IC2 library directory of this Instance
     */
    public File getIC2LibDirectory() {
        return new File(getModsDirectory(), "ic2");
    }

    /**
     * Gets a File object for the denlib directory of this Instance.
     *
     * @return File object for the denlib directory of this Instance
     */
    public File getDenLibDirectory() {
        return new File(getModsDirectory(), "denlib");
    }

    /**
     * Gets a File object for the plugins directory of this Instance.
     *
     * @return File object for the plugins directory of this Instance
     */
    public File getPluginsDirectory() {
        return new File(getRootDirectory(), "plugins");
    }

    /**
     * Gets a File object for the shader packs directory of this Instance.
     *
     * @return File object for the shader packs directory of this Instance
     */
    public File getShaderPacksDirectory() {
        return new File(getRootDirectory(), "shaderpacks");
    }

    /**
     * Gets a File object for the disabled mods directory of this Instance.
     *
     * @return File object for the disabled mods directory of this Instance
     */
    public File getDisabledModsDirectory() {
        return new File(getRootDirectory(), "disabledmods");
    }

    /**
     * Gets a File object for the core mods directory of this Instance.
     *
     * @return File object for the core mods directory of this Instance
     */
    public File getCoreModsDirectory() {
        return new File(getRootDirectory(), "coremods");
    }

    /**
     * Gets a File object for the jar mods directory of this Instance.
     *
     * @return File object for the jar mods directory of this Instance
     */
    public File getJarModsDirectory() {
        return new File(getRootDirectory(), "jarmods");
    }

    /**
     * Gets a File object for the texture packs directory of this Instance.
     *
     * @return File object for the texture packs directory of this Instance
     */
    public File getTexturePacksDirectory() {
        return new File(getRootDirectory(), "texturepacks");
    }

    /**
     * Gets a File object for the resource packs directory of this Instance.
     *
     * @return File object for the resource packs directory of this Instance
     */
    public File getResourcePacksDirectory() {
        return new File(getRootDirectory(), "resourcepacks");
    }

    /**
     * Gets a File object for the bin directory of this Instance.
     *
     * @return File object for the bin directory of this Instance
     */
    public File getBinDirectory() {
        return new File(getRootDirectory(), "bin");
    }

    /**
     * Gets a File object for the natives directory of this Instance.
     *
     * @return File object for the natives directory of this Instance
     */
    public File getNativesDirectory() {
        return new File(getBinDirectory(), "natives");
    }

    /**
     * Gets a File object for the minecraft.jar of this Instance.
     *
     * @return File object for the minecraft.jar of this Instance
     */
    public File getMinecraftJar() {
        return new File(getBinDirectory(), "minecraft.jar");
    }

    /**
     * Checks if the pack associated with this Instance can be installed.
     *
     * @return true if the Pack this Instance was made from can be installed
     * @see com.atlauncher.data.Pack#canInstall
     */
    public boolean canInstall() {
        return (this.realPack != null && this.realPack.canInstall());
    }

    /**
     * Gets the Pack object that this Instance was created from. If it doesn't exist, this will return null
     *
     * @return Pack object of the Pack this Instance was created from or null if no longer available
     */
    public Pack getRealPack() {
        return this.realPack;
    }

    /**
     * Sets the Pack object that this Instance was created from. Defaults to null when loaded.
     *
     * @param realPack the Pack object that this Instance was created from
     */
    public void setRealPack(Pack realPack) {
        this.realPack = realPack;
    }

    /**
     * Checks if this Instance has installed jar mods.
     *
     * @return true if there are jar mods
     */
    public boolean hasJarMods() {
        return this.jarOrder != null;
    }

    /**
     * Sets the minimum recommended PermGen/Metaspace size for this Instance in MB.
     *
     * @param permgen the minimum recommended PermGen/Metaspace for this Instance in MB
     */
    public void setPermgen(int permgen) {
        this.permgen = permgen;
    }

    /**
     * Sets this Instance as playable after it is marked unplayable and has been rectified.
     */
    public void setPlayable() {
        this.isPlayable = true;
    }

    /**
     * Sets this Instance as unplayable so the user cannot play the Instance. Used when installs go bad or files are
     * found that corrupts the Instance
     */
    public void setUnplayable() {
        this.isPlayable = false;
    }

    /**
     * Sets this Instance as a dev version.
     */
    public void setDevVersion() {
        this.isDev = true;
    }

    /**
     * Sets this Instance as a non dev version.
     */
    public void setNotDevVersion() {
        this.isDev = false;
        this.hash = null;
    }

    /**
     * Sets this Instances hash for dev versions.
     */
    public void setHash(String hash) {
        this.hash = hash;
    }

    /**
     * Checks if the version of the Pack this Instance was created from was a dev version.
     *
     * @return true if the version of the Pack used to create this Instance was a dev version
     */
    public boolean isDev() {
        return this.isDev;
    }

    /**
     * Checks if the Instance is playable.
     *
     * @return true if the Instance is playable
     */
    public boolean isPlayable() {
        return this.isPlayable;
    }

    /**
     * Sets the launch method used to launch this Instance.
     *
     * @param newLaunchMethod true if the new launch menthod should be used, false for the legacy launch method
     */
    public void setIsNewLaunchMethod(boolean newLaunchMethod) {
        this.newLaunchMethod = newLaunchMethod;
    }

    /**
     * Checks if this Instance uses the new launch method or not.
     *
     * @return true if this Instance uses the new launch method
     */
    public boolean isNewLaunchMethod() {
        return this.newLaunchMethod;
    }

    /**
     * Gets the libraries needed to be loaded when launching Minecraft.
     *
     * @return a comma separated list of filenames for the libraries to be loaded when Minecraft is started
     */
    public String getLibrariesNeeded() {
        return this.librariesNeeded;
    }

    /**
     * Sets the list of libraries needed to be loaded when launching Minecraft.
     *
     * @param librariesNeeded a comma separated list of filenames for the libraries to be loaded when Minecraft is
     *                        started
     */
    public void setLibrariesNeeded(String librariesNeeded) {
        this.librariesNeeded = librariesNeeded;
    }

    /**
     * Checks if there are extra arguments set for this Instance.
     *
     * @return true if there are set extra arguments for this Instance
     */
    public boolean hasExtraArguments() {
        return this.extraArguments != null;
    }

    /**
     * Gets the extra arguments for the Instance which is added to the command argument when launching Minecraft.
     *
     * @return the extra arguments used by the Instance when launching Minecraft
     */
    public String getExtraArguments() {
        return this.extraArguments;
    }

    /**
     * Sets the extra arguments for the Instance which is added to the command argument when launching Minecraft.
     *
     * @param extraArguments the new extra arguments used by the Instance when launching Minecraft
     */
    public void setExtraArguments(String extraArguments) {
        this.extraArguments = extraArguments;
    }

    /**
     * Checks if there are Minecraft arguments set for this Instance.
     *
     * @return true if there are set Minecraft arguments for this Instance
     */
    public boolean hasMinecraftArguments() {
        return this.minecraftArguments != null;
    }

    /**
     * Gets the Minecraft arguments for the Instance which is added to the command argument when launching Minecraft.
     * These involve things like asset directories, token input among other things.
     *
     * @return the Minecraft arguments used by the Instance when launching Minecraft
     */
    public String getMinecraftArguments() {
        return this.minecraftArguments;
    }

    /**
     * Sets the Minecraft arguments for the Instance which is added to the command argument when launching Minecraft.
     * These involve things like asset directories, token input among other things.
     *
     * @param minecraftArguments the new Minecraft arguments used by the Instance when launching Minecraft
     */
    public void setMinecraftArguments(String minecraftArguments) {
        this.minecraftArguments = minecraftArguments;
    }

    /**
     * Gets the main class used to launch Minecraft.
     *
     * @return the main class used to launch Minecraft
     */
    public String getMainClass() {
        return this.mainClass;
    }

    /**
     * Sets the main class used to launch Minecraft.
     *
     * @param mainClass the new main class used to launch Minecraft
     */
    public void setMainClass(String mainClass) {
        this.mainClass = mainClass;
    }

    /**
     * Gets the assets value which Minecraft uses to determine how to load assets in the game.
     *
     * @return the assets value
     */
    public String getAssets() {
        return (this.assets == null ? "legacy" : this.assets);
    }

    /**
     * Sets the assets value which Minecraft uses to determine how to load assets in the game.
     *
     * @param assets the new assets value
     */
    public void setAssets(String assets) {
        this.assets = assets;
    }

    /**
     * Checks if this Instance can be played. This refers only to the account and permission side of things and doesn't
     * reference if the instance is playable or as determined by the {@link com.atlauncher.data.Instance#isPlayable}
     * field.
     *
     * @return true if the user can play this Instance
     */
    public boolean canPlay() {
        // Make sure an account is selected first.
        if (App.settings.getAccount() == null || !App.settings.getAccount().isReal()) {
            return false;
        }

        // Check to see if this was a private Instance belonging to a specific user only.
        if (this.installedBy != null && !App.settings.getAccount().getMinecraftUsername().equalsIgnoreCase(this
                .installedBy)) {
            return false;
        }

        // All good, no false returns yet so allow it.
        return true;
    }

    /**
     * Checks if the Pack this Instance was created from has an update.
     *
     * @return true if there is an update to the Pack this Instance was created from
     */
    public boolean hasUpdate() {
        // Check to see if there is a Pack object defined first.
        if (this.realPack != null) {
            // Then check if the Pack has any versions associated with it and were NOT running a dev
            // version, as dev versions should never be updated.
            if (this.realPack.hasVersions() && !isDev()) {
                // Lastly check if the current version we installed is different than the latest
                // version of the Pack and that the latest version of the Pack is not restricted to
                // disallow updates.
                if (!this.realPack.getLatestVersion().getVersion().equalsIgnoreCase(this.version) && !this.realPack
                        .isLatestVersionNoUpdate()) {
                    return true;
                }
            }
            if (isDev() && (this.hash != null)) {
                PackVersion devVersion = this.realPack.getDevVersionByName(this.version);
                if (devVersion != null && !devVersion.hashMatches(this.hash)) {
                    return true;
                }
            }
        }

        // If we triggered nothing then there is no update.
        return false;
    }

    /**
     * Gets the latest version of the Pack this Instance was created from. If the Pack has been removed or it has no
     * published versions then it will return null.
     *
     * @return the latest version of the Pack this Instance was created from or null if the Pack no longer exists or
     * there is no versions of the Pack
     */
    public String getLatestVersion() {
        return (this.realPack != null ? this.realPack.getLatestVersion().getVersion() : null);
    }

    /**
     * Checks is a mod was installed with this Instance.
     *
     * @param name the name of the mod
     * @return true if the mod was installed with the Instance
     */
    public boolean wasModInstalled(String name) {
        if (this.mods != null) {
            for (DisableableMod mod : this.mods) {
                if (mod.getName().equalsIgnoreCase(name)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Sets the mods installed for this Instance.
     *
     * @param mods List of {@link com.atlauncher.data.DisableableMod} objects of the mods installed with this Instance.
     */
    public void setModsInstalled(List<DisableableMod> mods) {
        this.mods = mods;
    }

    /**
     * Starts the process to launch this Instance.
     *
     * @return true if the Minecraft process was started
     */
    public boolean launch() {
        final Account account = App.settings.getAccount();
        if (account == null) {
            String[] options = {Language.INSTANCE.localize("common.ok")};
            JOptionPane.showOptionDialog(App.settings.getParent(), Language.INSTANCE.localize("instance.noaccount"),
                    Language.INSTANCE.localize("instance.noaccountselected"), JOptionPane.DEFAULT_OPTION, JOptionPane
                            .ERROR_MESSAGE, null, options, options[0]);
            App.settings.setMinecraftLaunched(false);
            return false;
        } else {
            if ((App.settings.getMaximumMemory() < this.memory) && (this.memory <= Utils.getSafeMaximumRam())) {
                String[] options = {Language.INSTANCE.localize("common.yes"), Language.INSTANCE.localize("common.no")};
                int ret = JOptionPane.showOptionDialog(App.settings.getParent(), "<html><p align=\"center\">" +
                        Language.INSTANCE.localizeWithReplace("instance" + "" +
                                ".insufficientram", "<b>" + this.memory + "</b> MB<br/><br/>") +
                        "</p></html>", Language.INSTANCE.localize("instance.insufficientramtitle"), JOptionPane
                        .DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE, null, options, options[0]);
                if (ret != 0) {
                    LogManager.warn("Launching of instance cancelled due to user cancelling memory warning!");
                    App.settings.setMinecraftLaunched(false);
                    return false;
                }
            }
            if (App.settings.getPermGen() < this.permgen) {
                String[] options = {Language.INSTANCE.localize("common.yes"), Language.INSTANCE.localize("common.no")};
                int ret = JOptionPane.showOptionDialog(App.settings.getParent(), "<html><p align=\"center\">" +
                        Language.INSTANCE.localizeWithReplace("instance" + "" +
                                ".insufficientpermgen", "<b>" + this.permgen + "</b> MB<br/><br/>") +
                        "</p></html>", Language.INSTANCE.localize("instance.insufficientpermgentitle"), JOptionPane
                        .DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE, null, options, options[0]);
                if (ret != 0) {
                    LogManager.warn("Launching of instance cancelled due to user cancelling permgen warning!");
                    App.settings.setMinecraftLaunched(false);
                    return false;
                }
            }
            AuthenticationResponse sess = null;
            if (account.hasAccessToken() && account.isAccessTokenValid()) {
                LogManager.info("Access token checked and is valid!");
                sess = account.refreshToken();
            } else {
                if (account.hasAccessToken()) {
                    LogManager.error("Access token checked and is NOT valid! Will attempt to get another one!");
                    account.setAccessToken(null);
                    App.settings.saveAccounts();
                }
                String password = account.getPassword();
                if (!account.isRemembered()) {
                    JPanel panel = new JPanel();
                    panel.setLayout(new BorderLayout());
                    JLabel passwordLabel = new JLabel(Language.INSTANCE.localizeWithReplace("instance.enterpassword",
                            account.getMinecraftUsername()));
                    JPasswordField passwordField = new JPasswordField();
                    panel.add(passwordLabel, BorderLayout.NORTH);
                    panel.add(passwordField, BorderLayout.CENTER);
                    int ret = JOptionPane.showConfirmDialog(App.settings.getParent(), panel, Language.INSTANCE
                            .localize("instance.enterpasswordtitle"), JOptionPane.OK_CANCEL_OPTION);
                    if (ret == JOptionPane.OK_OPTION) {
                        password = new String(passwordField.getPassword());
                    } else {
                        LogManager.error("Aborting login for " + account.getMinecraftUsername());
                        App.settings.setMinecraftLaunched(false);
                        return false;
                    }
                }
                LogManager.info("Logging into Minecraft!");
                final String pass = password;
                final ProgressDialog dialog = new ProgressDialog(Language.INSTANCE.localize("account.loggingin"), 0,
                        Language.INSTANCE.localize("account.loggingin"), "Aborting login for " + account
                        .getMinecraftUsername());
                dialog.addThread(new Thread() {
                    public void run() {
                        dialog.setReturnValue(Authentication.checkAccount(account.getUsername(), pass, (account
                                .hasAccessToken() ? account.getClientToken() : null)));
                        dialog.close();
                    }
                });
                dialog.start();
                sess = (AuthenticationResponse) dialog.getReturnValue();
            }
            if (sess == null) {
                sess = new AuthenticationResponse("token:0:0", false);
            } else if (sess.hasError()) {
                LogManager.error(sess.getErrorMessage());
                String[] options = {Language.INSTANCE.localize("common.ok")};
                JOptionPane.showOptionDialog(App.settings.getParent(), "<html><p align=\"center\">" + Language
                        .INSTANCE.localizeWithReplace("instance.errorloggingin", "<br/><br/>" + sess.getErrorMessage
                                ()) + "</p></html>", Language.INSTANCE.localize("instance.errorloggingintitle"),
                        JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE, null, options, options[0]);
                App.settings.setMinecraftLaunched(false);
                return false;
            } else {
                account.setAccessToken(sess.getAccessToken());
                account.setClientToken(sess.getClientToken());
                account.setUUID(sess.getSelectedProfile().getId());
                App.settings.saveAccounts();
            }

            final AuthenticationResponse session = sess;
            Thread launcher = new Thread() {
                public void run() {
                    try {
                        long start = System.currentTimeMillis();
                        if (App.settings.getParent() != null) {
                            App.settings.getParent().setVisible(false);
                        }
                        // Create a note of worlds for auto backup if enabled
                        HashMap<String, Long> preWorldList = new HashMap<String, Long>();
                        if (App.settings.isAdvancedBackupsEnabled() && App.settings.getAutoBackup()) {
                            if (getSavesDirectory().exists()) {
                                File[] files = getSavesDirectory().listFiles();
                                if (files != null) {
                                    for (File file : files) {
                                        if (file.isDirectory()) {
                                            preWorldList.put(file.getName(), file.lastModified());
                                        }
                                    }
                                }
                            }
                        }
                        Process process = null;
                        if (isNewLaunchMethod()) {
                            process = MCLauncher.launch(account, Instance.this, session);
                        } else {
                            process = LegacyMCLauncher.launch(account, Instance.this, session);
                        }
                        App.settings.showKillMinecraft(process);
                        InputStream is = process.getInputStream();
                        InputStreamReader isr = new InputStreamReader(is);
                        BufferedReader br = new BufferedReader(isr);
                        String line;
                        while ((line = br.readLine()) != null) {
                            if (!LogManager.showDebug) {
                                line = line.replace(account.getMinecraftUsername(), "**MINECRAFTUSERNAME**");
                                line = line.replace(account.getUsername(), "**MINECRAFTUSERNAME**");
                                if (account.hasAccessToken()) {
                                    line = line.replace(account.getAccessToken(), "**ACCESSTOKEN**");
                                }
                                if (account.hasClientToken()) {
                                    line = line.replace(account.getClientToken(), "**CLIENTTOKEN**");
                                }
                                if (account.hasUUID()) {
                                    line = line.replace(account.getUUID(), "**UUID**");
                                }
                            }
                            LogManager.minecraft(line);
                        }
                        App.settings.hideKillMinecraft();
                        if (App.settings.getParent() != null && App.settings.keepLauncherOpen()) {
                            App.settings.getParent().setVisible(true);
                        }
                        long end = System.currentTimeMillis();
                        if (App.settings.isInOfflineMode()) {
                            App.settings.checkOnlineStatus();
                        }
                        int exitValue = 0; // Assume we exited fine
                        try {
                            exitValue = process.exitValue(); // Try to get the real exit value
                        } catch (IllegalThreadStateException e) {
                            App.settings.logStackTrace(e);
                            process.destroy(); // Kill the process
                        }
                        if (!App.settings.keepLauncherOpen()) {
                            App.settings.getConsole().setVisible(false); // Hide the console to
                            // pretend
                            // we've closed
                        }
                        if (exitValue != 0) {
                            // Submit any pending crash reports from Open Eye if need to since we
                            // exited abnormally
                            if (App.settings.enableLogs() && App.settings.enableOpenEyeReporting()) {
                                App.TASKPOOL.submit(new Runnable() {
                                    public void run() {
                                        sendOpenEyePendingReports();
                                    }
                                });
                            }
                        } else if (App.settings.isAdvancedBackupsEnabled() && App.settings.getAutoBackup()) {
                            // Begin backup
                            if (getSavesDirectory().exists()) {
                                File[] files = getSavesDirectory().listFiles();
                                if (files != null) {
                                    for (File file : files) {
                                        if ((file.isDirectory()) && (!file.getName().equals("NEI"))) {
                                            if (preWorldList.containsKey(file.getName())) {
                                                // Only backup if file changed
                                                if (!(preWorldList.get(file.getName()) == file.lastModified())) {
                                                    SyncAbstract sync = SyncAbstract.syncList.get(App.settings
                                                            .getLastSelectedSync());
                                                    sync.backupWorld(file.getName() + String.valueOf(file
                                                            .lastModified()), file, Instance.this);
                                                }
                                            }
                                            // Or backup if a new file is found
                                            else {
                                                SyncAbstract sync = SyncAbstract.syncList.get(App.settings
                                                        .getLastSelectedSync());
                                                sync.backupWorld(file.getName() + String.valueOf(file.lastModified())
                                                        .replace(":", ""), file, Instance.this);
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        App.settings.setMinecraftLaunched(false);
                        if (!App.settings.isInOfflineMode()) {
                            if (isLeaderboardsEnabled() && isLoggingEnabled() && !isDev() && App.settings.enableLogs
                                    ()) {
                                final int timePlayed = (int) (end - start) / 1000;
                                if (timePlayed > 0) {
                                    App.TASKPOOL.submit(new Runnable() {
                                        public void run() {
                                            addTimePlayed(timePlayed, (isDev ? "dev" : getVersion()));
                                        }
                                    });
                                }
                            }
                            if (App.settings.keepLauncherOpen() && App.settings.hasUpdatedFiles()) {
                                App.settings.reloadLauncherData();
                            }
                        }
                        if (!App.settings.keepLauncherOpen()) {
                            System.exit(1);
                        }
                    } catch (IOException e1) {
                        App.settings.logStackTrace(e1);
                    }
                }
            };
            launcher.start();
            return true;
        }
    }

    /**
     * Send open eye pending reports from the instance.
     */
    public void sendOpenEyePendingReports() {
        File reportsDir = this.getReportsDirectory();
        if (reportsDir.exists()) {
            for (String filename : reportsDir.list(Utils.getOpenEyePendingReportsFileFilter())) {
                File report = new File(reportsDir, filename);
                LogManager.info("OpenEye: Sending pending crash report located at '" + report.getAbsolutePath() + "'");
                OpenEyeReportResponse response = Utils.sendOpenEyePendingReport(report);
                if (response == null) {
                    // Pending report was never sent due to an issue. Won't delete the file in case
                    // it's
                    // a temporary issue and can be sent again later.
                    LogManager.error("OpenEye: Couldn't send pending crash report!");
                } else {
                    // OpenEye returned a response to the report, display that to user if needed.
                    LogManager.info("OpenEye: Pending crash report sent! URL: " + response.getURL());
                    if (response.hasNote()) {
                        String[] options = {Language.INSTANCE.localize("common.opencrashreport"), Language.INSTANCE
                                .localize("common.ok")};
                        int ret = JOptionPane.showOptionDialog(App.settings.getParent(), "<html><p align=\"center\">"
                                + Language.INSTANCE.localizeWithReplace("instance" + "" +
                                ".openeyereport1", "<br/><br/>") + response.getNoteDisplay() + Language.INSTANCE
                                .localize("instance.openeyereport2") + "</p></html>", Language.INSTANCE.localize
                                ("instance.aboutyourcrash"), JOptionPane.DEFAULT_OPTION, JOptionPane
                                .INFORMATION_MESSAGE, null, options, options[1]);
                        if (ret == 0) {
                            Utils.openBrowser(response.getURL());
                        }
                    }
                }
                Utils.delete(report); // Delete the pending report since we've sent it
            }
        }
    }

    public String addTimePlayed(int time, String version) {
        Map<String, Object> request = new HashMap<String, Object>();

        if (App.settings.enableLeaderboards()) {
            request.put("username", App.settings.getAccount().getMinecraftUsername());
        } else {
            request.put("username", null);
        }
        request.put("version", version);
        request.put("time", time);

        try {
            return Utils.sendAPICall("pack/" + getRealPack().getSafeName() + "/timeplayed/", request);
        } catch (IOException e) {
            App.settings.logStackTrace(e);
        }
        return "Leaderboard Time Not Added!";
    }

    /**
     * Clones a given instance of this class.
     *
     * @return Instance The cloned instance
     * @see java.lang.Object#clone()
     */
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            App.settings.logStackTrace(e);
        }
        return null;
    }

    public boolean hasCustomMods() {
        for (DisableableMod mod : this.mods) {
            if (mod.isUserAdded()) {
                return true;
            }
        }
        return false;
    }

    public List<String> getCustomMods(Type type) {
        List<String> customMods = new ArrayList<String>();
        for (DisableableMod mod : this.mods) {
            if (mod.isUserAdded() && mod.getType() == type) {
                customMods.add(mod.getFilename());
            }
        }
        return customMods;
    }

    public List<DisableableMod> getCustomDisableableMods() {
        List<DisableableMod> customMods = new ArrayList<DisableableMod>();
        for (DisableableMod mod : this.mods) {
            if (mod.isUserAdded()) {
                customMods.add(mod);
            }
        }
        return customMods;
    }

    public void save() {
        try {
            FileWriter writer = null;
            try {
                writer = new FileWriter(new File(new File(App.settings.getInstancesDir(), this.getSafeName()),
                        "instance.json"));
                writer.write(Gsons.DEFAULT.toJson(this));
                writer.flush();
                App.TOASTER.pop("Instance " + this.getName());
            } finally {
                if (writer != null) {
                    writer.close();
                }
            }
        } catch (IOException e) {
            e.printStackTrace(System.err);
        }
    }
}
TOP

Related Classes of com.atlauncher.data.Instance

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.