001 package cpw.mods.fml.relauncher; 002 003 import java.applet.Applet; 004 import java.io.File; 005 import java.lang.reflect.Method; 006 import java.net.URLClassLoader; 007 008 import javax.swing.JDialog; 009 import javax.swing.JOptionPane; 010 011 public class FMLRelauncher 012 { 013 private static FMLRelauncher INSTANCE; 014 public static String logFileNamePattern; 015 private static String side; 016 private RelaunchClassLoader classLoader; 017 private Object newApplet; 018 private Class<? super Object> appletClass; 019 020 JDialog popupWindow; 021 022 public static void handleClientRelaunch(ArgsWrapper wrap) 023 { 024 logFileNamePattern = "ForgeModLoader-client-%g.log"; 025 side = "CLIENT"; 026 instance().relaunchClient(wrap); 027 } 028 029 public static void handleServerRelaunch(ArgsWrapper wrap) 030 { 031 logFileNamePattern = "ForgeModLoader-server-%g.log"; 032 side = "SERVER"; 033 instance().relaunchServer(wrap); 034 } 035 036 static FMLRelauncher instance() 037 { 038 if (INSTANCE == null) 039 { 040 INSTANCE = new FMLRelauncher(); 041 } 042 return INSTANCE; 043 044 } 045 046 private FMLRelauncher() 047 { 048 URLClassLoader ucl = (URLClassLoader) getClass().getClassLoader(); 049 050 classLoader = new RelaunchClassLoader(ucl.getURLs()); 051 052 } 053 054 private void showWindow(boolean showIt) 055 { 056 if (RelaunchLibraryManager.downloadMonitor != null) { return; } 057 try 058 { 059 RelaunchLibraryManager.downloadMonitor = new Downloader(); 060 if (showIt) 061 { 062 popupWindow = RelaunchLibraryManager.downloadMonitor.makeDialog(); 063 } 064 } 065 catch (Exception e) 066 { 067 if (RelaunchLibraryManager.downloadMonitor == null) 068 { 069 e.printStackTrace(); 070 } 071 popupWindow = null; 072 RelaunchLibraryManager.downloadMonitor.makeHeadless(); 073 } 074 } 075 076 private void relaunchClient(ArgsWrapper wrap) 077 { 078 showWindow(true); 079 // Now we re-inject the home into the "new" minecraft under our control 080 Class<? super Object> client; 081 try 082 { 083 File minecraftHome = computeExistingClientHome(); 084 setupHome(minecraftHome); 085 086 client = setupNewClientHome(minecraftHome); 087 } 088 finally 089 { 090 if (popupWindow != null) 091 { 092 popupWindow.setVisible(false); 093 popupWindow.dispose(); 094 } 095 } 096 097 if (RelaunchLibraryManager.downloadMonitor.stopIt) 098 { 099 System.exit(1); 100 } 101 try 102 { 103 ReflectionHelper.findMethod(client, null, new String[] { "fmlReentry" }, ArgsWrapper.class).invoke(null, wrap); 104 } 105 catch (Exception e) 106 { 107 e.printStackTrace(); 108 // Hmmm 109 } 110 } 111 112 private Class<? super Object> setupNewClientHome(File minecraftHome) 113 { 114 Class<? super Object> client = ReflectionHelper.getClass(classLoader, "net.minecraft.client.Minecraft"); 115 ReflectionHelper.setPrivateValue(client, null, minecraftHome, "minecraftDir", "am", "minecraftDir"); 116 return client; 117 } 118 119 private void relaunchServer(ArgsWrapper wrap) 120 { 121 showWindow(false); 122 // Now we re-inject the home into the "new" minecraft under our control 123 Class<? super Object> server; 124 File minecraftHome = new File("."); 125 setupHome(minecraftHome); 126 127 server = ReflectionHelper.getClass(classLoader, "net.minecraft.server.MinecraftServer"); 128 try 129 { 130 ReflectionHelper.findMethod(server, null, new String[] { "fmlReentry" }, ArgsWrapper.class).invoke(null, wrap); 131 } 132 catch (Exception e) 133 { 134 e.printStackTrace(); 135 } 136 } 137 138 private void setupHome(File minecraftHome) 139 { 140 FMLInjectionData.build(minecraftHome, classLoader); 141 FMLRelaunchLog.minecraftHome = minecraftHome; 142 FMLRelaunchLog.info("Forge Mod Loader version %s.%s.%s.%s for Minecraft client:%s, server:%s loading", FMLInjectionData.major, FMLInjectionData.minor, 143 FMLInjectionData.rev, FMLInjectionData.build, FMLInjectionData.mccversion, FMLInjectionData.mcsversion); 144 145 try 146 { 147 RelaunchLibraryManager.handleLaunch(minecraftHome, classLoader); 148 } 149 catch (Throwable t) 150 { 151 if (popupWindow != null) 152 { 153 try 154 { 155 String logFile = new File(minecraftHome, "ForgeModLoader-client-0.log").getCanonicalPath(); 156 JOptionPane.showMessageDialog(popupWindow, String.format( 157 "<html><div align=\"center\"><font size=\"+1\">There was a fatal error starting up minecraft and FML</font></div><br/>" 158 + "Minecraft cannot launch in it's current configuration<br/>" 159 + "Please consult the file <i><a href=\"file:///%s\">%s</a></i> for further information</html>", logFile, logFile), 160 "Fatal FML error", JOptionPane.ERROR_MESSAGE); 161 } 162 catch (Exception ex) 163 { 164 // ah well, we tried 165 } 166 } 167 throw new RuntimeException(t); 168 } 169 } 170 171 /** 172 * @return 173 */ 174 private File computeExistingClientHome() 175 { 176 Class<? super Object> mcMaster = ReflectionHelper.getClass(getClass().getClassLoader(), "net.minecraft.client.Minecraft"); 177 // If we get the system property we inject into the old MC, setup the 178 // dir, then pull the value 179 String str = System.getProperty("minecraft.applet.TargetDirectory"); 180 if (str != null) 181 { 182 str = str.replace('/', File.separatorChar); 183 ReflectionHelper.setPrivateValue(mcMaster, null, new File(str), "minecraftDir", "am", "minecraftDir"); 184 } 185 // We force minecraft to setup it's homedir very early on so we can 186 // inject stuff into it 187 Method setupHome = ReflectionHelper.findMethod(mcMaster, null, new String[] { "getMinecraftDir", "getMinecraftDir", "b" }); 188 try 189 { 190 setupHome.invoke(null); 191 } 192 catch (Exception e) 193 { 194 // Hmmm 195 } 196 File minecraftHome = ReflectionHelper.getPrivateValue(mcMaster, null, "minecraftDir", "am", "minecraftDir"); 197 return minecraftHome; 198 } 199 200 public static void appletEntry(Applet minecraftApplet) 201 { 202 side = "CLIENT"; 203 logFileNamePattern = "ForgeModLoader-client-%g.log"; 204 instance().relaunchApplet(minecraftApplet); 205 } 206 207 private void relaunchApplet(Applet minecraftApplet) 208 { 209 showWindow(true); 210 211 appletClass = ReflectionHelper.getClass(classLoader, "net.minecraft.client.MinecraftApplet"); 212 if (minecraftApplet.getClass().getClassLoader() == classLoader) 213 { 214 if (popupWindow != null) 215 { 216 popupWindow.setVisible(false); 217 popupWindow.dispose(); 218 } 219 try 220 { 221 newApplet = minecraftApplet; 222 ReflectionHelper.findMethod(appletClass, newApplet, new String[] { "fmlInitReentry" }).invoke(newApplet); 223 return; 224 } 225 catch (Exception e) 226 { 227 System.out.println("FMLRelauncher.relaunchApplet"); 228 e.printStackTrace(); 229 throw new RuntimeException(e); 230 } 231 } 232 233 File mcDir = computeExistingClientHome(); 234 setupHome(mcDir); 235 setupNewClientHome(mcDir); 236 237 Class<? super Object> parentAppletClass = ReflectionHelper.getClass(getClass().getClassLoader(), "java.applet.Applet"); 238 239 try 240 { 241 newApplet = appletClass.newInstance(); 242 Object appletContainer = ReflectionHelper.getPrivateValue(ReflectionHelper.getClass(getClass().getClassLoader(), "java.awt.Component"), 243 minecraftApplet, "parent"); 244 245 String launcherClassName = System.getProperty("minecraft.applet.WrapperClass", "net.minecraft.Launcher"); 246 Class<? super Object> launcherClass = ReflectionHelper.getClass(getClass().getClassLoader(), launcherClassName); 247 if (launcherClass.isInstance(appletContainer)) 248 { 249 ReflectionHelper.findMethod(ReflectionHelper.getClass(getClass().getClassLoader(), "java.awt.Container"), minecraftApplet, 250 new String[] { "removeAll" }).invoke(appletContainer); 251 ReflectionHelper.findMethod(launcherClass, appletContainer, new String[] { "replace" }, parentAppletClass).invoke(appletContainer, newApplet); 252 } 253 else 254 { 255 FMLRelaunchLog.severe("Found unknown applet parent %s, unable to inject!\n", appletContainer.getClass().getName()); 256 throw new RuntimeException(); 257 } 258 } 259 catch (Exception e) 260 { 261 throw new RuntimeException(e); 262 } 263 finally 264 { 265 if (popupWindow != null) 266 { 267 popupWindow.setVisible(false); 268 popupWindow.dispose(); 269 } 270 } 271 } 272 273 public static void appletStart(Applet applet) 274 { 275 instance().startApplet(applet); 276 } 277 278 private void startApplet(Applet applet) 279 { 280 if (applet.getClass().getClassLoader() == classLoader) 281 { 282 if (popupWindow != null) 283 { 284 popupWindow.setVisible(false); 285 popupWindow.dispose(); 286 } 287 if (RelaunchLibraryManager.downloadMonitor.stopIt) 288 { 289 System.exit(1); 290 } 291 try 292 { 293 ReflectionHelper.findMethod(appletClass, newApplet, new String[] { "fmlStartReentry" }).invoke(newApplet); 294 } 295 catch (Exception e) 296 { 297 System.out.println("FMLRelauncher.startApplet"); 298 e.printStackTrace(); 299 throw new RuntimeException(e); 300 } 301 } 302 return; 303 } 304 305 public static String side() 306 { 307 return side; 308 } 309 }