diff --git a/src/main/java/org/dimdev/riftloader/RiftLoader.java b/src/main/java/org/dimdev/riftloader/RiftLoader.java index 8facf0e..2f3869c 100644 --- a/src/main/java/org/dimdev/riftloader/RiftLoader.java +++ b/src/main/java/org/dimdev/riftloader/RiftLoader.java @@ -8,10 +8,12 @@ import org.dimdev.accesstransform.AccessTransformer; import org.dimdev.riftloader.listener.InitializationListener; import org.dimdev.riftloader.listener.Instantiator; +import org.dimdev.riftloader.swing.GuiModLoaderProgress; import org.dimdev.utils.InstanceListMap; import org.dimdev.utils.InstanceMap; import org.dimdev.utils.ReflectionUtils; +import javax.annotation.Nullable; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -20,6 +22,7 @@ import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; +import java.nio.file.Files; import java.util.*; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -48,10 +51,11 @@ public void load(boolean isClient) { loaded = true; side = isClient ? Side.CLIENT : Side.SERVER; - - findMods(modsDir); - sortMods(); - initMods(); + GuiModLoaderProgress gui = null; + if (isClient) gui = new GuiModLoaderProgress(750, 250); + findMods(modsDir, gui); + sortMods(gui); + initMods(gui); initAccessTransformer(); } @@ -60,10 +64,11 @@ public void load(boolean isClient) { * the 'modsDir' directory (creating it if it doesn't exist) and loads them * into the 'modInfoMap'. **/ - private void findMods(File modsDir) { + private void findMods(File modsDir, @Nullable GuiModLoaderProgress gui) { // Load classpath mods log.info("Searching mods on classpath"); try { + if (gui != null) gui.updateProgressText("Finding classpath mods..."); Enumeration urls = ClassLoader.getSystemResources("riftmod.json"); while (urls.hasMoreElements()) { URL url = urls.nextElement(); @@ -81,10 +86,10 @@ private void findMods(File modsDir) { url = new URL(spec.substring(0, separator)); - loadModFromJson(in, new File(url.toURI())); + loadModFromJson(in, new File(url.toURI()), gui); break; case "file": - loadModFromJson(in, new File(url.toURI()).getParentFile()); + loadModFromJson(in, new File(url.toURI()).getParentFile(), gui); break; default: throw new RuntimeException("Unsupported protocol: " + url); @@ -96,8 +101,12 @@ private void findMods(File modsDir) { // Load jar mods log.info("Searching for mods in " + modsDir); + if (gui != null) gui.updateProgressText("Finding mods in " + modsDir); modsDir.mkdirs(); - for (File file : modsDir.listFiles()) { + File[] modDirFiles = modsDir.listFiles(); + int c = 0; + for (File file : modDirFiles) { + if (gui != null) gui.setProgress(c, modDirFiles.length); if (!file.getName().endsWith(".jar")) continue; try (JarFile jar = new JarFile(file)) { @@ -106,11 +115,12 @@ private void findMods(File modsDir) { JarEntry entry = jar.getJarEntry("riftmod.json"); if (entry != null) { - loadModFromJson(jar.getInputStream(entry), file); + loadModFromJson(jar.getInputStream(entry), file, gui); continue; } if (jar.getJarEntry("optifine/OptiFineClassTransformer.class") != null) { + if (gui != null) gui.updateProgressText("Loading OptiFine"); ModInfo mod = new ModInfo(); mod.source = file; mod.id = "optifine"; @@ -118,6 +128,7 @@ private void findMods(File modsDir) { mod.authors.add("sp614x"); mod.listeners.add(new ModInfo.Listener("org.dimdev.riftloader.OptifineLoader")); modInfoMap.put("optifine", mod); + if (gui != null) gui.updateProgressText("Finding mods in " + modsDir); } log.debug("Skipping " + file + " since it does not contain riftmod.json"); @@ -126,15 +137,16 @@ private void findMods(File modsDir) { } catch (Throwable t) { log.error("Exception while checking if file " + file + " is a mod", t); } + c++; } - log.info("Loaded " + modInfoMap.size() + " mods"); } - private void loadModFromJson(InputStream in, File source) { + private void loadModFromJson(InputStream in, File source, @Nullable GuiModLoaderProgress gui) { try { // Parse the 'riftmod.json' and make a ModInfo ModInfo modInfo = ModInfo.GSON.fromJson(new InputStreamReader(in), ModInfo.class); + if (gui != null) gui.updateProgressText("Reading " + modInfo.name + " (" + source.getName() + ")..."); modInfo.source = source; // Make sure the id isn't null and there aren't any duplicates @@ -148,20 +160,25 @@ private void loadModFromJson(InputStream in, File source) { // Add the mod to the 'id -> mod info' map modInfoMap.put(modInfo.id, modInfo); log.info("Loaded mod '" + modInfo.id + "'"); + if (gui != null) gui.updateProgressText("Read " + modInfo.name + " (" + modInfo.id + ")..."); } catch (JsonParseException e) { + if (gui != null) gui.updateProgressText(source.getName() + " was an invalid mod, skipping..."); throw new RuntimeException("Could not read riftmod.json in " + source, e); } } - private void sortMods() { + private void sortMods(@Nullable GuiModLoaderProgress gui) { + if (gui != null) gui.updateProgressText("Sorting mods..."); log.debug("Sorting mods"); } - private void initMods() { + private void initMods(@Nullable GuiModLoaderProgress gui) { + if (gui != null) gui.updateProgressText("Initialising mods..."); log.info("Initializing mods"); // Load all the mod jars for (ModInfo modInfo : modInfoMap.values()) { try { + if (gui != null) gui.updateProgressText("Initialising " + modInfo.name); addURLToClasspath(modInfo.source.toURI().toURL()); } catch (MalformedURLException e) { throw new RuntimeException(e); @@ -169,7 +186,11 @@ private void initMods() { } // Load the listener classes - for (ModInfo modInfo : modInfoMap.values()) { + Collection modInfos = modInfoMap.values(); + int c = 0; + for (ModInfo modInfo : modInfos) { + if (gui != null) gui.updateProgressText("Starting listeners for " + modInfo.name); + if (gui != null) gui.setProgress(c, modInfos.size()); if (modInfo.listeners != null) { for (ModInfo.Listener listener : modInfo.listeners) { if (listener.side.includes(side)) { @@ -183,6 +204,7 @@ private void initMods() { } } } + c++; } for (InitializationListener listener : getListeners(InitializationListener.class)) { @@ -190,6 +212,9 @@ private void initMods() { } log.info("Done initializing mods"); + if (gui != null) gui.updateProgressText("Done! Continuting to initialise Minecraft..."); + if (gui != null) gui.setProgress(1,1); + if (gui != null) gui.close(1500L); } private static void addURLToClasspath(URL url) { diff --git a/src/main/java/org/dimdev/riftloader/swing/GuiModLoaderProgress.java b/src/main/java/org/dimdev/riftloader/swing/GuiModLoaderProgress.java new file mode 100644 index 0000000..f844eef --- /dev/null +++ b/src/main/java/org/dimdev/riftloader/swing/GuiModLoaderProgress.java @@ -0,0 +1,79 @@ +package org.dimdev.riftloader.swing; + +import javax.swing.*; +import java.awt.*; + +public class GuiModLoaderProgress { + + private JLabel progressMessage = new JLabel("Initialising..."); + private JFrame mainFrame; + private JProgressBar progressBar; + + private int x; + private int y; + + public GuiModLoaderProgress(int x, int y) { + this.x = x; + this.y = y; + JFrame frame = new JFrame("Rift Mod Loader"); + frame.setLayout(null); + frame.setAutoRequestFocus(true); + frame.resize(this.x, this.y); + frame.setLocationRelativeTo(null); + frame.setResizable(false); + // + JLabel label = new JLabel("Rift Mod Loader is preparing your Minecraft environment..."); + label.setFont(new Font(label.getFont().getName(), Font.BOLD, 18)); + setPosition(frame, label, (this.x / 2) - getCenteredStringWidth(label), 40); + // + progressMessage.setFont(new Font(label.getFont().getName(), Font.PLAIN, 14)); + setPosition(frame, progressMessage, (this.x / 2 - getCenteredStringWidth(progressMessage)), this.y/2); + frame.add(label); + frame.add(progressMessage); + // + progressBar = new JProgressBar(); + progressBar.setPreferredSize(new Dimension(this.x - 50, 25)); + progressBar.setIndeterminate(true); + setPosition(frame, progressBar, (this.x / 2) - ((this.x - 50) / 2), this.y - 50); + frame.add(progressBar); + mainFrame = frame; + frame.setVisible(true); + } + + private void setPosition(JFrame pane, JComponent component, int x, int y) { + Insets insets = pane.getInsets(); + Dimension size = component.getPreferredSize(); + component.setBounds(new Rectangle(x + insets.left, y + insets.top, size.width, size.height)); + //return new Rectangle(x + insets.left, y + insets.top, size.width, size.height); + } + + private int getCenteredStringWidth(JLabel label) { + FontMetrics fm = label.getFontMetrics(label.getFont()); + return fm.stringWidth(label.getText()) / 2; + } + + public void updateProgressText(String info) { + progressMessage.setText(info); + setPosition(mainFrame, progressMessage, (this.x / 2 - getCenteredStringWidth(progressMessage)), this.y/2); + } + + public void close(long wait) { + try { + Thread.sleep(wait); + } catch (InterruptedException e) { + e.printStackTrace(); + } + mainFrame.setVisible(false); + } + + public void setProgress(int done, int total) { + if (done == -1) { + progressBar.setIndeterminate(true); + return; + } + progressBar.setIndeterminate(false); + progressBar.setMaximum(total); + progressBar.setValue(done); + } + +}