@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;
          }
        }
      }
    }