    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", "am", "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 client:%s, server:%s loading", FMLInjectionData.major, FMLInjectionData.minor,
    151                    FMLInjectionData.rev, FMLInjectionData.build, FMLInjectionData.mccversion, FMLInjectionData.mcsversion);
    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", "am", "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", "am", "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    }