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