package jk_5.nailed.launch; import net.minecraft.launchwrapper.Launch; import java.net.URL; import java.net.URLConnection; import java.nio.channels.Channels; import java.nio.channels.FileChannel; import java.nio.channels.ReadableByteChannel; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.security.DigestInputStream; import java.security.MessageDigest; public final class ServerMain { private static final String MINECRAFT_SERVER_LOCAL = "minecraft_server.1.8.jar"; private static final String MINECRAFT_SERVER_REMOTE = "https://s3.amazonaws.com/Minecraft.Download/versions/1.8/minecraft_server.1.8.jar"; private static final String LAUNCHWRAPPER_LOCAL = "launchwrapper-1.11.jar"; private static final String LAUNCHWRAPPER_REMOTE = "https://libraries.minecraft.net/net/minecraft/launchwrapper/1.11/launchwrapper-1.11.jar"; private static final String DEOBF_SRG_LOCAL = "deobf.srg.gz"; private static final String DEOBF_SRG_REMOTE = "https://github.com/nailed/nailed/raw/f48cb982537670e3d661fa86cc1d6de44315a053/config/joined.srg"; private static final String DEOBF_SRG_HASH = "93f72f87b5505dcbf1ce1c0f5b70f4fa"; // From http://stackoverflow.com/questions/9655181/convert-from-byte-array-to-hex-string-in-java private static final char[] hexArray = "0123456789abcdef".toCharArray(); public static void main(String[] args) throws Exception { if(!checkMinecraft()){ return; } Launch.main(join(args, "--tweakClass", "jk_5.nailed.launch.ServerTweaker" )); } private static String[] join(String[] args, String... prefix) { String[] result = new String[prefix.length + args.length]; System.arraycopy(prefix, 0, result, 0, prefix.length); System.arraycopy(args, 0, result, prefix.length, args.length); return result; } private static boolean checkMinecraft() throws Exception { Path bin = Paths.get("bin"); if (Files.notExists(bin)) { Files.createDirectories(bin); } // First check if Minecraft is already downloaded :D Path path = bin.resolve(MINECRAFT_SERVER_LOCAL); // Download the server first if (Files.notExists(path) && !downloadVerified(MINECRAFT_SERVER_REMOTE, path)) { return false; } path = bin.resolve(LAUNCHWRAPPER_LOCAL); if (Files.notExists(path) && !downloadVerified(LAUNCHWRAPPER_REMOTE, path)) { return false; } path = bin.resolve(DEOBF_SRG_LOCAL); return Files.exists(path) || downloadVerified(DEOBF_SRG_REMOTE, path, DEOBF_SRG_HASH); } private static boolean downloadVerified(String remote, Path path) throws Exception { return downloadVerified(remote, path, null); } private static boolean downloadVerified(String remote, Path path, String expected) throws Exception { String name = path.getFileName().toString(); boolean gzip = name.endsWith(".gz"); URL url = new URL(remote); System.out.println("Downloading " + name + "... This can take a while."); System.out.println(url); URLConnection con = url.openConnection(); if (gzip) { con.addRequestProperty("Accept-Encoding", "gzip"); } MessageDigest md5 = MessageDigest.getInstance("MD5"); try (ReadableByteChannel source = Channels.newChannel(new DigestInputStream(con.getInputStream(), md5)); FileChannel out = FileChannel.open(path, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)) { out.transferFrom(source, 0, Long.MAX_VALUE); } if (expected == null) { expected = getETag(con); } if (!expected.isEmpty()) { String hash = toHexString(md5.digest()); if (hash.equals(expected)) { System.out.println("Successfully downloaded " + name + " and verified checksum!"); } else { Files.delete(path); System.err.println("Failed to download " + name + " (failed checksum verification)."); System.err.println("Please try again later."); return false; } } return true; } private static String getETag(URLConnection con) { String hash = con.getHeaderField("ETag"); if (hash == null || hash.isEmpty()) { return ""; } if (hash.startsWith("\"") && hash.endsWith("\"")) { hash = hash.substring(1, hash.length() - 1); } return hash; } public static String toHexString(byte[] bytes) { char[] hexChars = new char[bytes.length * 2]; for (int j = 0; j < bytes.length; j++) { int v = bytes[j] & 0xFF; hexChars[j * 2] = hexArray[v >>> 4]; hexChars[j * 2 + 1] = hexArray[v & 0x0F]; } return new String(hexChars); } }