@Override public void run() { Asset asset; while ((asset = filesLeft.poll()) != null) { for (int i = 1; i < MAX_TRIES + 1; i++) { try { File file = new File(getAssetsDir(), "objects/" + asset.path); // does exist? create if (!file.exists()) { file.getParentFile().mkdirs(); file.createNewFile(); } File localMc = new File(minecraftDir, asset.path); BufferedInputStream stream; // check for local copy if (localMc.exists() && Constants.hash(localMc, "SHA1").equals(asset.hash)) // if so, copy stream = new BufferedInputStream(Files.newInputStreamSupplier(localMc).getInput()); else // otherwise download stream = new BufferedInputStream( new URL(Constants.ASSETS_URL + "/" + asset.path).openStream()); Files.write(ByteStreams.toByteArray(stream), file); stream.close(); // check hash... String hash = Constants.hash(file, "SHA1"); if (asset.hash.equals(hash)) break; // hashes are fine; else { file.delete(); getLogger() .error("download attempt " + i + " failed! : " + asset.hash + " != " + hash); } } catch (Exception e) { getLogger().error("Error downloading asset: " + asset.path); e.printStackTrace(); if (!errored) errored = true; } } } }
public String getMainClass() { return Constants.resolveString(mainClass); }
public String getRunDir() { return Constants.resolveString(runDir); }
public String getJvmArguments() { return Constants.resolveString(jvmArgs); }
public String getArguments() { return Constants.resolveString(runArgs); }
public String getProjectName() { return Constants.resolveString(projectName); }
public class DownloadAssetsTask extends DefaultTask { DelayedFile assetsDir; @Input Closure<AssetIndex> index; private boolean errored = false; private final ConcurrentLinkedQueue<Asset> filesLeft = new ConcurrentLinkedQueue<Asset>(); private final ArrayList<AssetsThread> threads = new ArrayList<AssetsThread>(); private final File minecraftDir = new File(Constants.getMinecraftDirectory(), "assets/objects"); private static final int MAX_THREADS = Runtime.getRuntime().availableProcessors(); private static final int MAX_TRIES = 5; @TaskAction public void doTask() throws ParserConfigurationException, SAXException, IOException, InterruptedException { File out = new File(getAssetsDir(), "objects"); out.mkdirs(); AssetIndex index = getIndex(); for (Entry<String, AssetEntry> e : index.objects.entrySet()) { Asset asset = new Asset(e.getValue().hash, e.getValue().size); File file = new File(out, asset.path); // exists but not the right size?? delete if (file.exists() && file.length() != asset.size) file.delete(); // does the file exist (still) ?? if (!file.exists()) filesLeft.offer(asset); } getLogger().info("Finished parsing JSON"); int max = filesLeft.size(); getLogger().info("Files Missing: " + max + "/" + index.objects.size()); // get number of threads int threadNum = max / 100; if (threadNum == 0 && max > 0) threadNum++; // atleats 1 thread // spawn threads for (int i = 0; i < threadNum; i++) spawnThread(); getLogger().info("Threads initially spawned: " + threadNum); while (stillRunning()) { int done = max - filesLeft.size(); getLogger() .lifecycle( "Current status: " + done + "/" + max + " " + (int) ((double) done / max * 100) + "%"); spawnThread(); Thread.sleep(1000); } if (errored) { // CRASH! getLogger().error("Something went wrong with the assets downloading!"); this.setDidWork(false); return; } } private void spawnThread() { if (threads.size() < MAX_THREADS) { getLogger().debug("Spawning thread #" + (threads.size() + 1)); AssetsThread thread = new AssetsThread(); thread.start(); threads.add(thread); } } private boolean stillRunning() { for (Thread t : threads) { if (t.isAlive()) { return true; } } getLogger().info("All " + threads.size() + " threads Complete"); return false; } public File getAssetsDir() { return assetsDir.call(); } public void setAssetsDir(DelayedFile assetsDir) { this.assetsDir = assetsDir; } public AssetIndex getIndex() { return index.call(); } public void setIndex(Closure<AssetIndex> index) { this.index = index; } private static class Asset { public final String path; public final String hash; public final long size; Asset(String hash, long size) { this.path = hash.substring(0, 2) + "/" + hash; this.hash = hash.toLowerCase(); this.size = size; } } private class AssetsThread extends Thread { public AssetsThread() { this.setDaemon(true); } @Override public void run() { Asset asset; while ((asset = filesLeft.poll()) != null) { for (int i = 1; i < MAX_TRIES + 1; i++) { try { File file = new File(getAssetsDir(), "objects/" + asset.path); // does exist? create if (!file.exists()) { file.getParentFile().mkdirs(); file.createNewFile(); } File localMc = new File(minecraftDir, asset.path); BufferedInputStream stream; // check for local copy if (localMc.exists() && Constants.hash(localMc, "SHA1").equals(asset.hash)) // if so, copy stream = new BufferedInputStream(Files.newInputStreamSupplier(localMc).getInput()); else // otherwise download stream = new BufferedInputStream( new URL(Constants.ASSETS_URL + "/" + asset.path).openStream()); Files.write(ByteStreams.toByteArray(stream), file); stream.close(); // check hash... String hash = Constants.hash(file, "SHA1"); if (asset.hash.equals(hash)) break; // hashes are fine; else { file.delete(); getLogger() .error("download attempt " + i + " failed! : " + asset.hash + " != " + hash); } } catch (Exception e) { getLogger().error("Error downloading asset: " + asset.path); e.printStackTrace(); if (!errored) errored = true; } } } } } }