Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Entrypoint hooks and mod messages #924

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
Draft
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package net.fabricmc.minecraft.test.info;

import net.fabricmc.loader.api.info.ProgressBar;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface DisplayRemote extends Remote {
void progressBars(ProgressBar[] progressBars) throws RemoteException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package net.fabricmc.minecraft.test.info;

import net.fabricmc.loader.api.info.ProgressBar;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;

public class DisplayRemoteObject extends UnicastRemoteObject implements DisplayRemote {
private ProgressBar[] progressBars = new ProgressBar[0];
protected DisplayRemoteObject() throws RemoteException {
new Thread(() -> {
JFrame frame = new JFrame();
frame.setVisible(false);
System.setProperty("apple.awt.application.appearance", "system");
System.setProperty("apple.awt.application.name", "Loading Window");

try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException |
UnsupportedLookAndFeelException e) {
throw new RuntimeException(e);
}
frame.setSize(480, 300);
frame.setVisible(true);
ConcurrentHashMap<String, JProgressBar> cache = new ConcurrentHashMap<>();
try {
while (true) {
int i = 0;
for (ProgressBar progressBar : progressBars) {
JProgressBar jProgressBar = cache.computeIfAbsent(progressBar.title(), f -> {
JProgressBar bar = progressBar.steps() == 0 ? new JProgressBar(0, 1) : new JProgressBar(0, progressBar.steps());
frame.add(bar);
return bar;
});
jProgressBar.setStringPainted(true);
if (progressBar.steps() == 0) jProgressBar.setValue(1);
jProgressBar.setString(progressBar.title() + " (" + progressBar.progress() + "/" + progressBar.steps() + ")");
jProgressBar.setBounds(10, 30 + i * 10, 300, 30 * 10);
if (progressBar.steps() != 0) jProgressBar.setValue(progressBar.progress());
i++;
}
frame.repaint();
cache.forEach((s, jProgressBar) -> {
if (Arrays.stream(progressBars).map(ProgressBar::title).noneMatch(s::equals)) {
frame.remove(jProgressBar);
cache.remove(s);
}
});
}
} catch (Throwable t) {
t.printStackTrace();
}
}).start();
}

@Override
public void progressBars(ProgressBar[] progressBars) {
this.progressBars = progressBars;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package net.fabricmc.minecraft.test.info;

import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint;
import net.fabricmc.loader.api.info.EntrypointInfoReceiver;
import net.fabricmc.loader.api.info.EntrypointInvocationSession;
import net.fabricmc.loader.api.info.Message;
import net.fabricmc.loader.api.info.ModMessageReceiver;
import net.fabricmc.loader.api.info.ProgressBar;
import net.fabricmc.loader.impl.util.LoaderUtil;
import net.fabricmc.loader.impl.util.UrlUtil;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.Arrays;
import java.util.concurrent.ConcurrentLinkedDeque;

@SuppressWarnings("InfiniteLoopStatement")
public class EarlyDisplayEntrypoint implements PreLaunchEntrypoint, Runnable, EntrypointInfoReceiver, ModMessageReceiver {

private DisplayRemote remote;

@Override
public void onPreLaunch() {
try {
openForked();
Thread.sleep(1000);
Registry registry = LocateRegistry.getRegistry(null, 1099);
System.out.println(Arrays.toString(registry.list()));
remote = (DisplayRemote) registry.lookup("Remote");
} catch (NotBoundException | InterruptedException | IOException e) {
throw new RuntimeException(e);
}
new Thread(this).start();

new Thread(() -> {
ProgressBar progressBar = FabricLoader.getInstance().getModMessageSession().progressBar("Test Progress Bar", 1000);
for (int i = 0; i < 1000; i++) {
progressBar.increment();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
progressBar.close();
}).start();
FabricLoader.getInstance().invokeEntrypoints("test", Runnable.class, Runnable::run);
}

private static void openForked() throws IOException, InterruptedException {
Path javaBinDir = LoaderUtil.normalizePath(Paths.get(System.getProperty("java.home"), "bin"));
String[] executables = { "javaw.exe", "java.exe", "java" };
Path javaPath = null;

for (String executable : executables) {
Path path = javaBinDir.resolve(executable);

if (Files.isRegularFile(path)) {
javaPath = path;
break;
}
}

if (javaPath == null) throw new RuntimeException("can't find java executable in " + javaBinDir);
Process process = new ProcessBuilder(javaPath.toString(), "-Xmx1G", "-cp", UrlUtil.getCodeSource(EarlyDisplayInit.class).toString() + ":" + UrlUtil.LOADER_CODE_SOURCE.toString(), EarlyDisplayInit.class.getName())
.redirectOutput(ProcessBuilder.Redirect.INHERIT)
.redirectError(ProcessBuilder.Redirect.INHERIT)
.start();

final Thread shutdownHook = new Thread(process::destroy);

Runtime.getRuntime().addShutdownHook(shutdownHook);
}

private static final ConcurrentLinkedDeque<ProgressBar> progressBars = new ConcurrentLinkedDeque<>();
private static final ConcurrentLinkedDeque<Message> pinnedMessages = new ConcurrentLinkedDeque<>();
private static final ConcurrentLinkedDeque<Message> messages = new ConcurrentLinkedDeque<>();

@Override
public void run() {
while (true) {
progressBars.removeIf(ProgressBar::isCompleted);
try {
remote.progressBars(progressBars.toArray(new ProgressBar[0]));
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
}

@Override
public EntrypointInvocationSession createEntrypointInvocationSession(String entrypointName, int size) {
TestEntrypointInvocationSession testEntrypointInvocationSession = new TestEntrypointInvocationSession();
testEntrypointInvocationSession.progressBar = FabricLoader.getInstance().getModMessageSession().progressBar(entrypointName, size);
return testEntrypointInvocationSession;
}

@Override
public void progressBar(ProgressBar progressBar) {
synchronized (progressBars) {
progressBars.add(progressBar);
}
}

@Override
public void message(Message message) {
synchronized (pinnedMessages) {
pinnedMessages.add(message);
}
}

private static class TestEntrypointInvocationSession implements EntrypointInvocationSession {
private ProgressBar progressBar;

@Override
public void preInvoke(ModContainer mod, int index, int size) {
progressBar.set(index);
}

@Override
public Throwable error(ModContainer mod, Throwable throwable, int index, int size) {
return throwable;
}

@Override
public void close() {
progressBar.close();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package net.fabricmc.minecraft.test.info;

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class EarlyDisplayInit {
public static void main(String[] args) throws RemoteException {
Registry registry = LocateRegistry.createRegistry(1099);
registry.rebind("Remote", new DisplayRemoteObject());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package net.fabricmc.minecraft.test.info;

public class TestEntrypoint implements Runnable {
@Override
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
34 changes: 34 additions & 0 deletions minecraft/minecraft-test/src/main/resources/fabric.mod.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,40 @@
"entrypoints": {
"main": [
"net.fabricmc.minecraft.test.TestEntrypoint"
],
"preLaunch": [
"net.fabricmc.minecraft.test.info.EarlyDisplayEntrypoint"
],
"entrypointReceiver": [
"net.fabricmc.minecraft.test.info.EarlyDisplayEntrypoint"
],
"modMessageReceiver": [
"net.fabricmc.minecraft.test.info.EarlyDisplayEntrypoint"
],
"test": [
"net.fabricmc.minecraft.test.info.TestEntrypoint",
"net.fabricmc.minecraft.test.info.TestEntrypoint",
"net.fabricmc.minecraft.test.info.TestEntrypoint",
"net.fabricmc.minecraft.test.info.TestEntrypoint",
"net.fabricmc.minecraft.test.info.TestEntrypoint",
"net.fabricmc.minecraft.test.info.TestEntrypoint",
"net.fabricmc.minecraft.test.info.TestEntrypoint",
"net.fabricmc.minecraft.test.info.TestEntrypoint",
"net.fabricmc.minecraft.test.info.TestEntrypoint",
"net.fabricmc.minecraft.test.info.TestEntrypoint",
"net.fabricmc.minecraft.test.info.TestEntrypoint",
"net.fabricmc.minecraft.test.info.TestEntrypoint",
"net.fabricmc.minecraft.test.info.TestEntrypoint",
"net.fabricmc.minecraft.test.info.TestEntrypoint",
"net.fabricmc.minecraft.test.info.TestEntrypoint",
"net.fabricmc.minecraft.test.info.TestEntrypoint",
"net.fabricmc.minecraft.test.info.TestEntrypoint",
"net.fabricmc.minecraft.test.info.TestEntrypoint",
"net.fabricmc.minecraft.test.info.TestEntrypoint",
"net.fabricmc.minecraft.test.info.TestEntrypoint",
"net.fabricmc.minecraft.test.info.TestEntrypoint",
"net.fabricmc.minecraft.test.info.TestEntrypoint",
"net.fabricmc.minecraft.test.info.TestEntrypoint"
]
}
}
5 changes: 5 additions & 0 deletions src/main/java/net/fabricmc/loader/api/FabricLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

import net.fabricmc.api.EnvType;
import net.fabricmc.loader.api.entrypoint.EntrypointContainer;
import net.fabricmc.loader.api.info.EntrypointInfoReceiver;
import net.fabricmc.loader.api.info.ModMessageSender;
import net.fabricmc.loader.impl.FabricLoaderImpl;

/**
Expand Down Expand Up @@ -236,4 +238,7 @@ static FabricLoader getInstance() {
* @return the launch arguments for the game
*/
String[] getLaunchArguments(boolean sanitize);

List<EntrypointInfoReceiver> getEntrypointInfoReceivers();
ModMessageSender getModMessageSession();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package net.fabricmc.loader.api.info;

public interface EntrypointInfoReceiver {
EntrypointInvocationSession createEntrypointInvocationSession(String entrypointName, int size);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package net.fabricmc.loader.api.info;

import net.fabricmc.loader.api.ModContainer;

import java.io.Closeable;

public interface EntrypointInvocationSession extends Closeable {
/**
* Called <b>before</b> an entrypoint is invoked.
*/
void preInvoke(ModContainer mod, int index, int size);
Throwable error(ModContainer mod, Throwable throwable, int index, int size);
@Override
void close();
}
14 changes: 14 additions & 0 deletions src/main/java/net/fabricmc/loader/api/info/Message.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package net.fabricmc.loader.api.info;

import java.io.Closeable;

public interface Message extends Closeable {
boolean pinned();
/**
* Sets a new message. Should only be used when pinned.
*/
void title(String message);
String title();
@Override
void close();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package net.fabricmc.loader.api.info;

public interface ModMessageReceiver {
void progressBar(ProgressBar progressBar);
void message(Message message);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package net.fabricmc.loader.api.info;

public interface ModMessageSender {
Message message(String string);

ProgressBar progressBar(String name, int steps);
}
34 changes: 34 additions & 0 deletions src/main/java/net/fabricmc/loader/api/info/ProgressBar.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package net.fabricmc.loader.api.info;

import org.jetbrains.annotations.Nullable;

import java.io.Closeable;

/**
* A progress bar with 0 is an indeterminate progress bar which can only be completed.
*/
public interface ProgressBar extends Closeable {
void increment();
float percentage();
int progress();

/**
* @return The total amount of steps the progress bar has.
*/
int steps();
void set(int steps);
String title();
void title(String title);
@Override
void close();

boolean isCompleted();

/**
* Create a child progress bar.
*/
ProgressBar progressBar(String name, int steps);

@Nullable
ProgressBar getParent();
}
Loading