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 }