    001package net.minecraft.util;
    002
    003import cpw.mods.fml.relauncher.Side;
    004import cpw.mods.fml.relauncher.SideOnly;
    005import java.io.DataInputStream;
    006import java.io.DataOutputStream;
    007import java.io.File;
    008import java.io.FileOutputStream;
    009import java.io.IOException;
    010import java.net.URL;
    011import java.net.URLConnection;
    012
    013import javax.xml.parsers.DocumentBuilder;
    014import javax.xml.parsers.DocumentBuilderFactory;
    015import net.minecraft.client.Minecraft;
    016import org.w3c.dom.Document;
    017import org.w3c.dom.Element;
    018import org.w3c.dom.Node;
    019import org.w3c.dom.NodeList;
    020
    021@SideOnly(Side.CLIENT)
    022public class ThreadDownloadResources extends Thread
    023{
    024    /** The folder to store the resources in. */
    025    public File resourcesFolder;
    026
    027    /** A reference to the Minecraft object. */
    028    private Minecraft mc;
    029
    030    /** Set to true when Minecraft is closing down. */
    031    private boolean closing = false;
    032
    033    public ThreadDownloadResources(File par1File, Minecraft par2Minecraft)
    034    {
    035        this.mc = par2Minecraft;
    036        this.setName("Resource download thread");
    037        this.setDaemon(true);
    038        this.resourcesFolder = new File(par1File, "resources/");
    039
    040        if (!this.resourcesFolder.exists() && !this.resourcesFolder.mkdirs())
    041        {
    042            throw new RuntimeException("The working directory could not be created: " + this.resourcesFolder);
    043        }
    044    }
    045
    046    public void run()
    047    {
    048        try
    049        {
    050            URL url = new URL("http://s3.amazonaws.com/MinecraftResources/");
    051            DocumentBuilderFactory documentbuilderfactory = DocumentBuilderFactory.newInstance();
    052            DocumentBuilder documentbuilder = documentbuilderfactory.newDocumentBuilder();
    053            //Add a timeout of 60 seconds to getting the list, MC stalls without sound for some users.
    054            URLConnection con = url.openConnection();
    055            con.setConnectTimeout(60000);
    056            con.setReadTimeout(60000);
    057            Document document = documentbuilder.parse(con.getInputStream());
    058            NodeList nodelist = document.getElementsByTagName("Contents");
    059
    060            for (int i = 0; i < 2; ++i)
    061            {
    062                for (int j = 0; j < nodelist.getLength(); ++j)
    063                {
    064                    Node node = nodelist.item(j);
    065
    066                    if (node.getNodeType() == 1)
    067                    {
    068                        Element element = (Element)node;
    069                        String s = element.getElementsByTagName("Key").item(0).getChildNodes().item(0).getNodeValue();
    070                        long k = Long.parseLong(element.getElementsByTagName("Size").item(0).getChildNodes().item(0).getNodeValue());
    071
    072                        if (k > 0L)
    073                        {
    074                            this.downloadAndInstallResource(url, s, k, i);
    075
    076                            if (this.closing)
    077                            {
    078                                return;
    079                            }
    080                        }
    081                    }
    082                }
    083            }
    084        }
    085        catch (Exception exception)
    086        {
    087            this.loadResource(this.resourcesFolder, "");
    088            exception.printStackTrace();
    089        }
    090    }
    091
    092    /**
    093     * Reloads the resource folder and passes the resources to Minecraft to install.
    094     */
    095    public void reloadResources()
    096    {
    097        this.loadResource(this.resourcesFolder, "");
    098    }
    099
    100    /**
    101     * Loads a resource and passes it to Minecraft to install.
    102     */
    103    private void loadResource(File par1File, String par2Str)
    104    {
    105        File[] afile = par1File.listFiles();
    106
    107        for (int i = 0; i < afile.length; ++i)
    108        {
    109            if (afile[i].isDirectory())
    110            {
    111                this.loadResource(afile[i], par2Str + afile[i].getName() + "/");
    112            }
    113            else
    114            {
    115                try
    116                {
    117                    this.mc.installResource(par2Str + afile[i].getName(), afile[i]);
    118                }
    119                catch (Exception exception)
    120                {
    121                    this.mc.getLogAgent().logWarning("Failed to add " + par2Str + afile[i].getName() + " in resources");
    122                }
    123            }
    124        }
    125    }
    126
    127    /**
    128     * Downloads the resource and saves it to disk then installs it.
    129     */
    130    private void downloadAndInstallResource(URL par1URL, String par2Str, long par3, int par5)
    131    {
    132        try
    133        {
    134            int k = par2Str.indexOf("/");
    135            String s1 = par2Str.substring(0, k);
    136
    137            if (s1.equalsIgnoreCase("sound3"))
    138            {
    139                if (par5 != 0)
    140                {
    141                    return;
    142                }
    143            }
    144            else if (par5 != 1)
    145            {
    146                return;
    147            }
    148
    149            File file1 = new File(this.resourcesFolder, par2Str);
    150
    151            if (!file1.exists() || file1.length() != par3)
    152            {
    153                file1.getParentFile().mkdirs();
    154                String s2 = par2Str.replaceAll(" ", "%20");
    155                this.downloadResource(new URL(par1URL, s2), file1, par3);
    156
    157                if (this.closing)
    158                {
    159                    return;
    160                }
    161            }
    162
    163            this.mc.installResource(par2Str, file1);
    164        }
    165        catch (Exception exception)
    166        {
    167            exception.printStackTrace();
    168        }
    169    }
    170
    171    /**
    172     * Downloads the resource and saves it to disk.
    173     */
    174    private void downloadResource(URL par1URL, File par2File, long par3) throws IOException
    175    {
    176        byte[] abyte = new byte[4096];
    177        //Add a timeout of 60 seconds to getting the list, MC stalls without sound for some users.
    178        URLConnection con = par1URL.openConnection();
    179        con.setConnectTimeout(60000);
    180        con.setReadTimeout(60000);
    181        DataInputStream datainputstream = new DataInputStream(con.getInputStream());
    182        DataOutputStream dataoutputstream = new DataOutputStream(new FileOutputStream(par2File));
    183        boolean flag = false;
    184
    185        do
    186        {
    187            int j;
    188
    189            if ((j = datainputstream.read(abyte)) < 0)
    190            {
    191                datainputstream.close();
    192                dataoutputstream.close();
    193                return;
    194            }
    195
    196            dataoutputstream.write(abyte, 0, j);
    197        }
    198        while (!this.closing);
    199    }
    200
    201    /**
    202     * Called when Minecraft is closing down.
    203     */
    204    public void closeMinecraft()
    205    {
    206        this.closing = true;
    207    }
    208}