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}