All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.minecraftforge.gradle.tasks.DownloadAssetsTask Maven / Gradle / Ivy

package net.minecraftforge.gradle.tasks;

import groovy.lang.Closure;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentLinkedQueue;

import javax.xml.parsers.ParserConfigurationException;

import net.minecraftforge.gradle.common.Constants;
import net.minecraftforge.gradle.delayed.DelayedFile;
import net.minecraftforge.gradle.delayed.DelayedString;
import net.minecraftforge.gradle.json.version.AssetIndex;
import net.minecraftforge.gradle.json.version.AssetIndex.AssetEntry;

import org.gradle.api.DefaultTask;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.TaskAction;
import org.xml.sax.SAXException;

import com.google.common.io.ByteStreams;
import com.google.common.io.Files;

public class DownloadAssetsTask extends DefaultTask
{
    DelayedFile                                assetsDir;

    @Input
    Closure                        index;

    @Input
    DelayedString                              indexName;

    private boolean                            errored      = false;
    private File                               virtualRoot  = null;
    private final ConcurrentLinkedQueue filesLeft    = new ConcurrentLinkedQueue();
    private final ArrayList      threads      = new ArrayList();
    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();

        // check virtual
        if (index.virtual)
        {
            virtualRoot = new File(getAssetsDir(), "virtual/" + getIndexName());
            virtualRoot.mkdirs();
        }

        for (Entry e : index.objects.entrySet())
        {
            Asset asset = new Asset(e.getKey(), e.getValue().hash, e.getValue().size);
            File file_hashed = new File(out, asset.path);
            File file_virtual = new File(virtualRoot, asset.name);

            // exists but not the right size?? delete
            if (file_hashed.exists() && file_hashed.length() != asset.size)
                file_hashed.delete();

            // File or virtual doesnt exist? add to the list.
            if (!file_hashed.exists())
            {
                filesLeft.offer(asset);
                continue;
            }

            if (index.virtual)
            {
                if (file_virtual.exists() && (file_virtual.length() != asset.size || !asset.hash.equalsIgnoreCase(Constants.hash(file_virtual, "SHA"))))
                {
                    file_virtual.delete();
                }

                if (!file_virtual.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 index)
    {
        this.index = index;
    }

    public String getIndexName()
    {
        return indexName.call();
    }

    public void setIndexName(DelayedString indexName)
    {
        this.indexName = indexName;
    }

    private static class Asset
    {
        public final String name;
        public final String path;
        public final String hash;
        public final long   size;

        Asset(String name, String hash, long size)
        {
            this.name = name;
            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);

                        if (file.exists() && file.length() != asset.size)
                        {
                            file.delete();
                        }

                        if (!file.exists())
                        {
                            file.getParentFile().mkdirs();

                            File localMc = new File(minecraftDir, asset.path);
                            BufferedInputStream stream;

                            // check for local copy
                            if (localMc.exists() && Constants.hash(localMc, "SHA").equals(asset.hash))
                                stream = new BufferedInputStream(Files.newInputStreamSupplier(localMc).getInput()); // if so, copy
                            else
                                stream = new BufferedInputStream(new URL(Constants.ASSETS_URL + "/" + asset.path).openStream()); // otherwise download

                            Files.write(ByteStreams.toByteArray(stream), file);
                            stream.close();
                        }

                        String hash = Constants.hash(file, "SHA");
                        if (asset.hash.equals(hash))
                        {
                            break;
                        }
                        else
                        {
                            file.delete();
                            getLogger().error("download attempt " + i + " failed! : " + asset.hash + " != " + hash);
                        }

                        // copy to virtual
                        if (virtualRoot != null)
                        {
                            File virtual = new File(virtualRoot, asset.name);
                            virtual.getParentFile().mkdirs();
                            if (virtual.exists() && !Constants.hash(virtual, "SHA").equalsIgnoreCase(asset.hash))
                            {
                                virtual.delete();
                            }

                            if (!virtual.exists())
                            {
                                Files.copy(file, virtual);
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        getLogger().error("Error downloading asset: " + asset.path);
                        e.printStackTrace();
                        if (!errored)
                        {
                            errored = true;
                        }
                    }
                }
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy