package pl.asiekierka.AsieLauncher.launcher;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.net.URL;
import java.util.*;
import java.util.logging.Level;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.json.simple.*;
import pl.asiekierka.AsieLauncher.common.IProgressUpdater;
import pl.asiekierka.AsieLauncher.common.JavaLauncher;
import pl.asiekierka.AsieLauncher.common.Utils;
import pl.asiekierka.AsieLauncher.download.AssetDownloader;
public class MinecraftHandler162 implements MinecraftHandler {
protected AssetDownloader assetDownloader;
protected IProgressUpdater updater;
protected String assetsDir;
protected JSONObject launchInfo;
protected String gameArguments, gameVersion;
protected ArrayList<String> libraries;
protected String mainClass, nativesDir;
protected boolean hasForge = false;
public MinecraftHandler162() {
// TODO Auto-generated constructor stub
}
public String getIndexName() { return "legacy"; }
public String getJarLocation(AsieLauncher l) {
File dir = new File(l.baseDir + "versions/" + l.mcVersion + "/");
if(!dir.exists()) dir.mkdirs();
return Utils.getPath(l.baseDir + "versions/" + l.mcVersion + "/minecraft.jar");
}
public String getStartJarLocation(AsieLauncher l) {
File f = new File(l.directory + "bin/minecraft.jar");
try {
if(f.exists()) return f.getCanonicalPath();
else return getJarLocation(l);
} catch(Exception e) {
return getJarLocation(l);
}
}
protected String getNativesLocation(AsieLauncher l) {
File dir = new File(l.baseDir + "versions/" + l.mcVersion + "/natives/");
if(!dir.exists()) dir.mkdirs();
return dir.getAbsolutePath();
}
public String findForge(File[] jarPatchFiles) {
if(jarPatchFiles != null) {
for(File f: jarPatchFiles) {
if(f.getName().startsWith("minecraftforge")) {
// Found it!
Utils.logger.log(Level.FINE, "Found an instance of Forge: " + f.getAbsolutePath());
return f.getAbsolutePath();
}
}
}
return null;
}
public void addTweak(String s, String version) {
if(version.equals("1.6.2")) addTweak162(s);
else gameArguments += " --tweakClass "+s;
}
protected void addTweak162(String s) {
if(gameArguments.indexOf("tweakClass") >= 0 || hasForge) {
gameArguments += " --cascadedTweaks "+s;
} else {
gameArguments += " --tweakClass "+s;
// Install the tweaker
Utils.logger.log(Level.WARNING, "TODO: INSTALL TWEAKER WITHOUT FORGE; MIGHT GET A BIT MESSY");
}
}
protected void scanLiteLoader(String modDir, String libraryDir, String version) {
try {
File[] loaderFiles = new File(modDir).listFiles();
if(loaderFiles == null) return;
for(File f: loaderFiles) {
if(f.getName().endsWith(".litemod")) {
Utils.logger.log(Level.INFO, "LiteLoader mod '" + f.getName() + "' found, downloading LiteLoader...");
addTweak("com.mumfrey.liteloader.launch.LiteLoaderTweaker", version);
downloadLibrary("http://dl.liteloader.com/versions/", "com.mumfrey",
"liteloader", version, libraryDir, false);
libraries.add(libraryDir+"liteloader-"+version+".jar");
return;
}
}
} catch(Exception e) { e.printStackTrace(); }
}
protected boolean downloadLibraries(String patchDir, String libraryDir) {
ArrayList<String> addedLibraries = new ArrayList<String>();
// Go through library files
File jarPatchesDirectory = new File(patchDir, "lib");
File[] jarPatchFiles = jarPatchesDirectory.listFiles();
if(jarPatchFiles != null) {
for(File f: jarPatchFiles) {
libraries.add(f.getAbsolutePath());
}
}
// Go through libraries in JSON file
JSONArray jsonLibraries = (JSONArray)launchInfo.get("libraries");
int imax = jsonLibraries.size();
int i = -1;
for(Object o: jsonLibraries) {
i++;
JSONObject jsonLibrary = (JSONObject)o;
String[] data = ((String)jsonLibrary.get("name")).split(":");
String uid = data[0] + ":" + data[1];
String filename = data[1] + "-" + data[2] + ".jar";
String addon = "";
if(updater != null) {
updater.update(i, imax);
}
if(addedLibraries.contains(uid)) continue; // We already have this lib
if(jsonLibrary.containsKey("natives")) {
// This is a /native/ file, so change filename
JSONObject nativeList = (JSONObject)jsonLibrary.get("natives");
addon = (String)nativeList.get(Utils.getSystemName());
filename = data[1] + "-" + data[2] + "-" + addon + ".jar";
}
String filePath = libraryDir + filename; // Don't move that above natives code.
String urlPrefix = "https://libraries.minecraft.net/";
if(jsonLibrary.containsKey("url"))
urlPrefix = (String)jsonLibrary.get("url");
if(!(new File(filePath).exists())) {
boolean found = false;
if(new File(jarPatchesDirectory, filename).exists()) { // We have one in custom
found = true;
hasForge = true;
filePath = new File(jarPatchesDirectory, filename).getAbsolutePath();
Utils.logger.log(Level.FINER, "Replacing library " + filename + " with local copy");
}
if(filename.startsWith("minecraftforge")) {
String forgeLocation = findForge(jarPatchFiles);
if(forgeLocation != null) {
filePath = forgeLocation;
found = true;
}
}
if(!found) downloadLibrary(urlPrefix, data[0], data[1], data[2], addon, libraryDir, false);
}
if(jsonLibrary.containsKey("natives") && !(filePath.indexOf("twitch") >= 0)) {
// This is a /native/ file, so extract it
try {
Utils.extract(filePath, nativesDir, true);
}
catch(Exception e) { e.printStackTrace(); return false; }
}
if(!filename.startsWith("minecraftforge")) libraries.add(filePath);
addedLibraries.add(uid);
}
// Go through "custom" libraries
File customFolder = new File(libraryDir, "custom");
File[] customLibraries = customFolder.listFiles();
for(File library : customLibraries) {
libraries.add(library.getAbsolutePath());
}
// All done.
return true;
}
public boolean downloadLibrary(String urlPrefix, String className, String name, String version, String libraryDir, boolean force) {
return this.downloadLibrary(urlPrefix, className, name, version, "", libraryDir, force);
}
public boolean downloadLibrary(String urlPrefix, String className, String name, String version, String addon, String libraryDir, boolean force) {
String filename = name + "-" + version + ".jar";
if(addon != null && addon.length() > 0)
filename = name + "-" + version + "-" + addon + ".jar";
// HACK! - 1.7.x do not download Twitch as it breaks
if(filename.indexOf("twitch") >= 0 && filename.indexOf("platform") >= 0)
return true;
// END HACK!
String filePath = libraryDir + filename;
if(libraries.contains(filePath)) return true; // Already downloaded
String urlPath = urlPrefix + (urlPrefix.endsWith("/")?"":"/") + className.replace('.', '/') + "/"
+ name + "/" + version + "/" + filename;
if(force || !(new File(filename)).exists()) {
if(updater != null) {
updater.setStatus(Strings.DOWNLOADING + " " + name + " " + version + "...");
}
try {
boolean downloaded = Utils.download(new URL(urlPath), filePath);
return downloaded;
} catch(Exception e) { e.printStackTrace(); return false; }
} else return true;
}
protected boolean loadJSON(String patchDir, String gameDir, String jsonDir, String version) {
if(launchInfo != null) return true; // Already been here
if(updater != null) {
updater.update(1, 2);
updater.setStatus(Strings.JSON_CHECKING);
}
// Try to find one in per-server libraries
boolean found = false;
File customFolder = new File(patchDir, "lib");
File[] customPatches = customFolder.listFiles();
if(new File(patchDir, "version.json").exists()) {
found = true;
try {
Utils.copyStream(new FileInputStream(new File(patchDir, "version.json")),
new FileOutputStream(new File(jsonDir)));
} catch(Exception e) { e.printStackTrace(); found = false; }
}
if(!found && customPatches != null) {
for(File patchFile: customPatches) {
if(found) break;
try {
for(String s: Utils.getZipList(patchFile.getAbsolutePath())) {
if(s.equals("version.json")) {
found = true; // Got one!
// Now to unpack it
ZipFile zip = new ZipFile(patchFile);
Enumeration<? extends ZipEntry> zipFileEntries = zip.entries();
while (zipFileEntries.hasMoreElements())
{
// grab a zip file entry
ZipEntry entry = (ZipEntry) zipFileEntries.nextElement();
String currentEntry = entry.getName();
if(!currentEntry.equals("version.json")) continue;
File destFile = new File(jsonDir);
Utils.copyStream(zip.getInputStream(entry), new FileOutputStream(destFile));
break;
}
zip.close();
break;
} else continue;
}
} catch(Exception e) { e.printStackTrace(); }
}
}
if(!found) {
// Download
try {
boolean downloaded = Utils.download(new URL("http://s3.amazonaws.com/Minecraft.Download/versions/"+version+"/"+version+".json"), jsonDir);
if(!downloaded) return false;
} catch(Exception e) { e.printStackTrace(); return false; }
}
// Load
launchInfo = Utils.readJSONFile(jsonDir);
if(launchInfo == null) return false;
// Parse
gameArguments = (String)launchInfo.get("minecraftArguments"); // Arguments are parsed in getMCArguments();
mainClass = (String)launchInfo.get("mainClass");
if(gameArguments.indexOf("cpw.mods.fml") >= 0) {
hasForge = true; // Found Forge in arguments
}
// Libraries
libraries = new ArrayList<String>();
scanLiteLoader(patchDir + "mods/", gameDir + "libraries/", version);
if(!downloadLibraries(patchDir, gameDir + "libraries/")) return false; // Get necessary libraries
return true;
}
public boolean downloadMinecraft(String location, String version) {
if(!(new File(location).exists())) {
try {
if(updater != null) updater.setStatus(Strings.DOWNLOADING+" Minecraft...");
boolean downloaded = Utils.download(new URL("http://s3.amazonaws.com/Minecraft.Download/versions/"+version+"/"+version+".jar"), location);
return downloaded;
} catch(Exception e) { e.printStackTrace(); return false; }
}
return true;
}
protected boolean checkMinecraft(AsieLauncher l) {
assetsDir = l.baseDir+"assets/";
gameVersion = l.mcVersion;
nativesDir = getNativesLocation(l);
File dir = new File(l.baseDir + "libraries/custom/");
if(!dir.exists()) dir.mkdirs();
if(!loadJSON(l.directory, l.baseDir, l.directory+"launchinfo.json", l.mcVersion)) return false;
if(!downloadMinecraft(getJarLocation(l), l.mcVersion)) return false;
return true;
}
@Override
public boolean download(AsieLauncher l) {
assetDownloader = new AssetDownloader(getIndexName(), updater);
assetsDir = l.baseDir+"assets/";
if(!assetDownloader.download(assetsDir)) return false;
if(!checkMinecraft(l)) return false;
return true;
}
protected String generateClasspath(AsieLauncher l) {
String classpathSeparator = ":";
if(Utils.getSystemName().equals("windows")) classpathSeparator = ";";
StringBuilder sb = new StringBuilder();
sb.append(getStartJarLocation(l)); // Minecraft.jar
if(libraries != null) {
for(String s : libraries) { // Libraries
sb.append(classpathSeparator);
sb.append(Utils.getPath(s));
}
}
return sb.toString();
}
@Override
public boolean isActive() {
return false; // We only launch via Java thread for now.
}
protected void setStatus(AsieLauncher l, String status) {
if(l.updater != null) l.updater.setStatus(status);
}
protected ArrayList<String> getMCArguments(AsieLauncher l, String path, String username, String sessionID, String UUID, String jvmArgs) {
ArrayList<String> args = new ArrayList<String>();
args.addAll(Arrays.asList(jvmArgs.split(" ")));
args.add("-cp"); args.add(generateClasspath(l));
args.add("-Djava.library.path=" + new File(nativesDir).getAbsolutePath());
args.add("-Dfml.ignorePatchDiscrepancies=true");
args.add("-Dfml.ignoreInvalidMinecraftCertificates=true");
args.add(mainClass);
// Parse gameArguments
gameArguments = gameArguments.replaceAll("\\$\\{auth_player_name\\}", username)
.replaceAll("\\$\\{auth_session\\}", "token:" + sessionID + ":" + UUID) //1.6.x auth_session is token:<AccessToken>:<PlayerUUID>
.replaceAll("\\$\\{version_name\\}", gameVersion);
if(l.mcVersion.equalsIgnoreCase("1.6.2")) { // 1.6.2 cascadedTweaks fix for old launchwrapper
if(gameArguments.indexOf("--cascadedTweaks") >= 0 // If we have more tweaks
&& gameArguments.indexOf("--tweakClass cpw.mods.fml.common.launcher.FMLTweaker") >= 0) {
gameArguments = gameArguments.replaceAll("--tweakClass cpw.mods.fml.common.launcher.FMLTweaker", "")
.replaceFirst("--cascadedTweaks", "--tweakClass")
+ " --cascadedTweaks cpw.mods.fml.common.launcher.FMLTweaker";
}
} else {
gameArguments = gameArguments.replaceAll("--cascadedTweaks", "--tweakClass");
}
// Workaround for broken Windows path handling
String[] gameArgArray = gameArguments.split(" ");
for(int i = 0; i < gameArgArray.length; i++) {
if(gameArgArray[i].equals("${game_directory}"))
gameArgArray[i] = Utils.getPath(new File(path).getAbsolutePath());
else if(gameArgArray[i].equals("${game_assets}"))
gameArgArray[i] = Utils.getPath(assetsDir);
}
args.addAll(Arrays.asList(gameArgArray));
Utils.logger.log(Level.INFO, "Launching with arguments: " + args.toString());
return args;
}
@Override
public boolean launch(String path, String username, String sessionID, String UUID, String jvmArgs, AsieLauncher l) {
if(!checkMinecraft(l)) return false;
if(sessionID == null || sessionID.length() == 0) sessionID = "null";
// Launch Minecraft.
setStatus(l, Strings.LAUNCHING);
return JavaLauncher.launch(path, getMCArguments(l, path, username, sessionID, UUID, jvmArgs));
}
public IProgressUpdater getUpdater() {
return updater;
}
public void setUpdater(IProgressUpdater updater) {
this.updater = updater;
}
}