package pl.asiekierka.AsieLauncher.launcher; import java.awt.Dimension; import java.io.*; import java.net.*; import java.util.*; import java.util.Map.Entry; import java.util.logging.ConsoleHandler; import java.util.logging.FileHandler; import java.util.logging.Level; import java.util.logging.Logger; import java.util.logging.SimpleFormatter; import javax.swing.ImageIcon; import net.minecraft.Launcher; import org.json.simple.*; import org.json.simple.parser.*; import org.smbarbour.mcu.*; import pl.asiekierka.AsieLauncher.auth.Authentication; import pl.asiekierka.AsieLauncher.auth.AuthenticationMojangLegacy; import pl.asiekierka.AsieLauncher.auth.AuthenticationYggdrasil; import pl.asiekierka.AsieLauncher.common.IProgressUpdater; import pl.asiekierka.AsieLauncher.common.Utils; import pl.asiekierka.AsieLauncher.download.FileDownloader; import pl.asiekierka.AsieLauncher.download.FileDownloaderHTTP; import pl.asiekierka.AsieLauncher.download.FileDownloaderZip; import pl.asiekierka.AsieLauncher.download.FileParserJSON; @SuppressWarnings("unused") public class AsieLauncher implements IProgressUpdater { public static final int VERSION = 8; private ServerListManager serverlist; public static final String VERSION_STRING = "0.4.7"; public String WINDOW_NAME = Strings.TITLE; public String URL = "http://asie.pl:5000/"; private String PREFIX = "default"; private ArrayList<FileDownloader> baseFiles; public String directory, baseDir; private String OS; private JSONObject file, oldFile, configFile; private int fullProgress, fullTotal; protected IProgressUpdater updater; private boolean launchedMinecraft = false; private String loadDir; private MinecraftHandler mc; private Authentication auth; public String mcVersion; public String defaultJvmArgs; public boolean canKeepPassword() { return (auth instanceof AuthenticationYggdrasil); } public void setKeepPassword(boolean l) { if(auth instanceof AuthenticationYggdrasil) { AuthenticationYggdrasil auth = (AuthenticationYggdrasil)this.auth; auth.setKeepPassword(l); } } public String getLoadDir() { return loadDir; } public IProgressUpdater getUpdater() { return updater; } public void setUpdater(IProgressUpdater updater) { this.updater = updater; } public boolean isOnlineMode() { return (auth != null); } public int getFileRevision(JSONObject source) { Long revNew = (Long)(source.get("client_revision")); if(revNew == null) return 1; return revNew.intValue(); } public boolean compatibleClientRevision() { if(file == null) return true; // Assumptions! Long revNew = (Long)(file.get("client_revision")); if(revNew == null) { return false; // Ancient } else return revNew.intValue() == VERSION; } public HashMap<String, JSONObject> getOptionMap() { HashMap<String, JSONObject> optionMap = new HashMap<String, JSONObject>(); if(file != null) { JSONObject options = (JSONObject)file.get("options"); for(Object o: options.values()) { JSONObject option = (JSONObject)o; optionMap.put((String)option.get("id"), option); } } return optionMap; } public void configureConfig() { configFile = Utils.readJSONUrlFile(getClass().getResource("/resources/config.json")); PREFIX = (String)configFile.get("directoryName"); URL = (String)configFile.get("serverUrl"); if(!URL.startsWith("http://") && (URL.indexOf("://") < 0)) { URL = "http://" + URL; } } public AsieLauncher() { configureConfig(); baseDir = System.getProperty("user.home") + "/.asielauncher/"; directory = baseDir + PREFIX + "/"; try { FileHandler handler = new FileHandler(Utils.getPath(directory + "AsieLauncher.log"), false); handler.setFormatter(new SimpleFormatter()); Utils.logger.addHandler(handler); } catch(Exception e) { e.printStackTrace(); } serverlist = new ServerListManager(directory + "servers.dat", false); if(!(new File(directory).exists())) { new File(directory).mkdirs(); } else { oldFile = Utils.readJSONFile(directory + "also.json"); } loadDir = (new File(".").getAbsolutePath()); loadDir = loadDir.substring(0,loadDir.length()-1); OS = Utils.getSystemName(); Utils.logger.log(Level.INFO, "OS: " + OS); } public boolean isSupported() { if(this.mcVersion == null) return true; // Default hack return Utils.versionToInt(this.mcVersion) <= Utils.versionToInt("1.7.10"); } public boolean init() { file = Utils.readJSONUrlFile(URL + "also.json"); if(!(file instanceof JSONObject)) { file = oldFile; } else System.out.println("Config revision: " + getFileRevision(file)); if(file instanceof JSONObject) { // Set variables;. Object o = file.get("onlineMode"); boolean onlineMode = false; if(o instanceof Boolean) onlineMode = ((Boolean)o); if(getFileRevision(file) >= 5) { mcVersion = (String)file.get("mcVersion"); if(getFileRevision(file) >= 6) { WINDOW_NAME = (String)file.get("windowName"); } else WINDOW_NAME = ""; } else mcVersion = "1.7.2"; if(Utils.versionToInt(this.mcVersion) <= Utils.versionToInt("1.5.2")) { mc = new MinecraftHandler152(); if(onlineMode) auth = new AuthenticationMojangLegacy(); } else { if (Utils.versionToInt(this.mcVersion) >= Utils.versionToInt("1.6.0") && Utils.versionToInt(this.mcVersion) < Utils.versionToInt("1.7.0") ) { mc = new MinecraftHandler162(); } else if (Utils.versionToInt(this.mcVersion) >= Utils.versionToInt("1.7.0") && Utils.versionToInt(this.mcVersion) < Utils.versionToInt("1.7.6") ) { mc = new MinecraftHandler172(); } else { mc = new MinecraftHandler1710(); } if(onlineMode) auth = new AuthenticationYggdrasil(directory, false); } if(file.containsKey("jvmArguments")) { defaultJvmArgs = (String)file.get("jvmArguments"); } return (file != oldFile); } return false; } public boolean askForPassword() { return (auth != null && auth.requiresPassword()); } public boolean save() { return Utils.saveStringToFile(directory + "also.json", file.toJSONString()); } public JSONObject getPlatformData(JSONObject source) { JSONObject platforms = (JSONObject)source.get("platforms"); return (JSONObject)platforms.get(OS); } public JSONObject getOptionData(JSONObject source, String id) { JSONObject options = (JSONObject)source.get("options"); return (JSONObject)options.get(id); } public void update(int progress, int total) { if(updater != null) updater.update((fullProgress+progress), fullTotal); if(progress == total) fullProgress += total; } public void setStatus(String status) { Utils.logger.log(Level.INFO, "Status: "+status); if(updater != null) updater.setStatus(status); } public ArrayList<FileDownloader> getFileList(JSONObject source, ArrayList<String> options) { FileParserJSON parser = new FileParserJSON(URL, directory); ArrayList<FileDownloader> files = parser.parse(source); if(mc instanceof MinecraftHandler152) { // 1.5.2 still downloads platform data. files.addAll(parser.parse(getPlatformData(source), "http", "platform/"+OS+"/")); } if(getFileRevision(source) >= 2) for(String id: options) { JSONObject data = getOptionData(source, id); if(data == null) continue; boolean doZip = (Boolean)data.get("zip"); files.addAll(parser.parse(data, doZip?"zip":"http", "options/"+id+"/")); } if(getFileRevision(source) >= 5) { JSONArray data = (JSONArray)source.get("jarPatches"); files.addAll(parser.parse(data, "http")); } Utils.logger.log(Level.FINER, "getFileList: got " + files.size() + " files"); return files; } public int calculateTotalSize(ArrayList<FileDownloader> files) { int totalSize = 0; for(FileDownloader mf: files) { totalSize += mf.getFilesize(); } return totalSize; } private ArrayList<String> installLog; public List<String> getRepackedFiles() { ArrayList<String> rf = new ArrayList<String>(); JSONArray data = (JSONArray)file.get("jarPatches"); for(Object o: data) { if(!(o instanceof JSONObject)) continue; JSONObject jo = (JSONObject)o; rf.add(directory + (String)jo.get("filename")); } return rf; } public String[] getInstallLog() { return installLog.toArray(new String[installLog.size()]); } public boolean install(boolean dry) { ArrayList<String> options = new ArrayList<String>(); ArrayList<String> oldOptions = new ArrayList<String>(); return install(options, oldOptions, dry); } public boolean authenticate(String username, String password) { if(auth != null) { setStatus(Strings.AUTH_STATUS); int result = auth.authenticate(username, password); if(result != Authentication.OK) { setStatus(Strings.LOGIN_ERROR+": " + auth.getErrorMessage()); return false; } else return true; } else return true; // No authentication core set, offline mode. } public boolean install(ArrayList<String> options, ArrayList<String> oldOptions, boolean dry) { ArrayList<FileDownloader> installFiles = getFileList(file, options); ArrayList<FileDownloader> oldInstallFiles = null; int dryTotal = 0; installLog = new ArrayList<String>(); if(oldFile != null) { oldInstallFiles = getFileList(oldFile, oldOptions); // Delete old files for(FileDownloader mf: oldInstallFiles) { if(!installFiles.contains(mf)) { if(dry && !(mf instanceof FileDownloaderZip)) { // Dry run installLog.add("[-] " + mf.getFilename()); dryTotal -= mf.getFilesize(); continue; } this.setStatus(Strings.REMOVING+" "+mf.getFilename()+"..."); if(!mf.remove()) { this.setStatus(Strings.REMOVING+" "+Strings.FAILED); return false; } } } } else oldInstallFiles = new ArrayList<FileDownloader>(); fullTotal = calculateTotalSize(installFiles); for(FileDownloader mf: installFiles) { if(dry && !mf.verify()) { dryTotal += mf.getFilesize(); if(mf instanceof FileDownloaderZip) { FileDownloaderZip mfz = (FileDownloaderZip) mf; installLog.add("[+] " + mfz.getFilename() + " => ./" + mfz.unpackLocation); } else { installLog.add("[+] " + mf.getFilename()); } continue; } else if(dry) continue; this.setStatus(Strings.INSTALLING+" "+mf.getFilename()+"..."); if(!mf.install(this)) { this.setStatus(Strings.INSTALLING+" "+Strings.FAILED); return false; } } if(dry) return true; this.setStatus(Strings.DOWNLOAD_MC); mc.setUpdater(updater); mc.download(this); Repacker repacker = new Repacker(directory + "bin/minecraft.jar"); List<String> repackFiles = getRepackedFiles(); this.setStatus(Strings.REPACK_JAR); String repackError = repacker.repackJar(mc.getJarLocation(this), repackFiles.toArray(new String[repackFiles.size()])); if(repackError != null) { this.setStatus(repackError); return false; } if(!dry) { this.setStatus(Strings.SAVING); this.save(); } else { installLog.add("Total installation size: " + Math.round(dryTotal/1024) + "KB"); } return true; } public boolean isActive() { return !launchedMinecraft || (mc != null && mc.isActive()); } public void launch(String _username, String password, String jvmArgs) { // Update serverlist. if(file != null) { if(updater != null) updater.setStatus(Strings.UPDATE_SERVERLIST); HashMap<String, String> servers = new HashMap<String, String>(); JSONObject serversJson = (JSONObject)file.get("servers"); for(Object o: serversJson.entrySet()) { if(!(o instanceof Entry)) continue; @SuppressWarnings("unchecked") Entry<? extends Object, ? extends Object> e = (Entry<? extends Object, ? extends Object>)o; // WTF, Java? if(!(e.getKey() instanceof String) || !(e.getValue() instanceof String)) continue; servers.put((String)e.getKey(), (String)e.getValue()); } serverlist.updateServerList(servers); } // Authenticate, if necessary. String username = _username; String sessionID = "null"; String uuidString = "null"; if(updater != null) updater.update(100,100); if(auth != null) { username = auth.getUsername(); sessionID = auth.getSessionToken(); uuidString = auth.getUUID(); } launchedMinecraft = mc.launch(directory, username, sessionID, uuidString, jvmArgs, this); } }