Skip to content
This repository was archived by the owner on Apr 28, 2020. It is now read-only.

Create a Swing window that shows mod loading progress at startup #49

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 39 additions & 14 deletions src/main/java/org/dimdev/riftloader/RiftLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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();
}

Expand All @@ -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<URL> urls = ClassLoader.getSystemResources("riftmod.json");
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
Expand All @@ -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);
Expand All @@ -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)) {
Expand All @@ -106,18 +115,20 @@ 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";
mod.name = "Optifine";
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");
Expand All @@ -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
Expand All @@ -148,28 +160,37 @@ 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);
}
}

// Load the listener classes
for (ModInfo modInfo : modInfoMap.values()) {
Collection<ModInfo> 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)) {
Expand All @@ -183,13 +204,17 @@ private void initMods() {
}
}
}
c++;
}

for (InitializationListener listener : getListeners(InitializationListener.class)) {
listener.onInitialization();
}

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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}

}