From b9295f7b4625ef3579f14b175c8f0553a88d03f4 Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 09:11:43 +0800
Subject: [PATCH 01/26] Add translation key method for available features
Refactor feature representation and add translation keys.
---
.../api/AvailableFeatures.java | 82 +++++--------------
1 file changed, 21 insertions(+), 61 deletions(-)
diff --git a/src/api/java/io/github/gaming32/modloadingscreen/api/AvailableFeatures.java b/src/api/java/io/github/gaming32/modloadingscreen/api/AvailableFeatures.java
index 580f0e4..8a8f6e0 100644
--- a/src/api/java/io/github/gaming32/modloadingscreen/api/AvailableFeatures.java
+++ b/src/api/java/io/github/gaming32/modloadingscreen/api/AvailableFeatures.java
@@ -3,58 +3,16 @@
import java.util.StringJoiner;
public final class AvailableFeatures {
- /**
- * @since 1.0.3
- * @see LoadingScreenApi#getFinalEntrypoints
- */
@SuppressWarnings("PointlessBitwiseExpression")
public static final long FINAL_ENTRYPOINTS = 1L << 0;
-
- /**
- * @since 1.0.3
- * @see LoadingScreenApi#isHeadless
- */
public static final long HEADLESS_CHECK = 1L << 1;
-
- /**
- * @since 1.0.3
- * @see LoadingScreenApi#isUsingIpc
- */
@Deprecated
public static final long IPC_CHECK = 1L << 2;
-
- /**
- * @since 1.0.3
- * @see LoadingScreenApi#getActiveProgressBars
- * @see LoadingScreenApi#getProgress
- */
public static final long GET_PROGRESS = 1L << 3;
-
- /**
- * @since 1.0.3
- * @see LoadingScreenApi#isOpen
- */
public static final long OPEN_CHECK = 1L << 4;
-
- /**
- * @since 1.0.4
- * @see LoadingScreenApi#getCustomProgressBar
- * @see CustomProgressBar
- */
public static final long CUSTOM_PROGRESS_BARS = 1L << 5;
- /**
- * All the features that should be available on version 1.0.3.
- *
- * @since 1.0.3
- */
public static final long V1_0_3 = FINAL_ENTRYPOINTS | HEADLESS_CHECK | IPC_CHECK | GET_PROGRESS | OPEN_CHECK;
-
- /**
- * All the features that should be available on version 1.0.4.
- *
- * @since 1.0.4
- */
public static final long V1_0_4 = V1_0_3 | CUSTOM_PROGRESS_BARS;
private static final long MIN_FEATURE = FINAL_ENTRYPOINTS;
@@ -63,37 +21,39 @@ public final class AvailableFeatures {
private AvailableFeatures() {
}
+ public static String getTranslationKey(long feature) {
+ switch ((int) feature) {
+ case (int) FINAL_ENTRYPOINTS:
+ return "modloadingscreen.feature.final_entrypoints";
+ case (int) HEADLESS_CHECK:
+ return "modloadingscreen.feature.headless_check";
+ case (int) IPC_CHECK:
+ return "modloadingscreen.feature.ipc_check";
+ case (int) GET_PROGRESS:
+ return "modloadingscreen.feature.get_progress";
+ case (int) OPEN_CHECK:
+ return "modloadingscreen.feature.open_check";
+ case (int) CUSTOM_PROGRESS_BARS:
+ return "modloadingscreen.feature.custom_progress_bars";
+ default:
+ return "modloadingscreen.feature.unknown";
+ }
+ }
+
public static String toString(long features) {
if (Long.bitCount(features) <= 1L) {
- switch ((int)features) {
- case (int)FINAL_ENTRYPOINTS:
- return "FINAL_ENTRYPOINTS";
- case (int)HEADLESS_CHECK:
- return "HEADLESS_CHECK";
- case (int)IPC_CHECK:
- return "IPC_CHECK";
- case (int)GET_PROGRESS:
- return "GET_PROGRESS";
- case (int)OPEN_CHECK:
- return "OPEN_CHECK";
- case (int)CUSTOM_PROGRESS_BARS:
- return "CUSTOM_PROGRESS_BARS";
- }
- return "";
+ return getTranslationKey(features);
}
final StringJoiner sj = new StringJoiner(", ");
for (long feature = MIN_FEATURE; feature <= MAX_FEATURE; feature <<= 1) {
if (hasFeatures(features, feature)) {
- sj.add(toString(feature));
+ sj.add(getTranslationKey(feature));
}
}
return sj.toString();
}
- /**
- * @see LoadingScreenApi#hasFeatures
- */
public static boolean hasFeatures(long supportedFeatures, long requestedFeatures) {
return (supportedFeatures & requestedFeatures) != 0;
}
From 36081a640c2fccf3e7c2bf96e549e756eb16b42c Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 09:12:30 +0800
Subject: [PATCH 02/26] Refactor CustomProgressBar to use titleKey and args
---
.../api/CustomProgressBar.java | 92 +++++--------------
1 file changed, 24 insertions(+), 68 deletions(-)
diff --git a/src/api/java/io/github/gaming32/modloadingscreen/api/CustomProgressBar.java b/src/api/java/io/github/gaming32/modloadingscreen/api/CustomProgressBar.java
index 7438595..388eccb 100644
--- a/src/api/java/io/github/gaming32/modloadingscreen/api/CustomProgressBar.java
+++ b/src/api/java/io/github/gaming32/modloadingscreen/api/CustomProgressBar.java
@@ -3,26 +3,23 @@
import java.io.Closeable;
import java.util.Objects;
-/**
- * A reference to a custom progress bar. Recommended to be used with try-with-resources.
- *
- * @see LoadingScreenApi#getCustomProgressBar
- */
public final class CustomProgressBar implements Closeable {
private final String id;
private final boolean isReal;
private boolean closed;
- private String title;
+ private String titleKey;
+ private String[] titleArgs;
private int progress;
private int minimum;
private int maximum;
private boolean indeterminate;
- CustomProgressBar(String id, boolean isReal, String title, int maximum) {
+ CustomProgressBar(String id, boolean isReal, String titleKey, int maximum, String... titleArgs) {
this.id = id;
this.isReal = isReal;
- this.title = title;
+ this.titleKey = titleKey;
+ this.titleArgs = titleArgs != null ? titleArgs : new String[0];
this.maximum = maximum;
}
@@ -40,9 +37,6 @@ private void checkClosed() {
}
}
- /**
- * Close the progress bar and remove it from the loading screen.
- */
@Override
public void close() {
if (LoadingScreenApi.CUSTOM_PROGRESS_BARS.remove(id) == this) {
@@ -50,10 +44,6 @@ public void close() {
}
}
- /**
- * Sets the progress of the progress bar. The new progress will be clamped to the {@code [minimum, maximum]} range.
- * @param progress The new progress.
- */
public void setProgress(int progress) {
progress = Math.min(maximum, Math.max(minimum, progress));
checkClosed();
@@ -62,36 +52,19 @@ public void setProgress(int progress) {
LoadingScreenApi.customProgressBarOp(id, "progress", Integer.toString(progress));
}
- /**
- * Gets the current progress of the progress bar.
- */
public int getProgress() {
return progress;
}
- /**
- * Steps the progress bar forward one step.
- *
- * @return The new progress of the progress bar, which may be clamped into range.
- */
public int step() {
return step(1);
}
- /**
- * Steps the progress bar forward {@code n} steps.
- *
- * @return The new progress of the progress bar, which may be clamped into range.
- */
public int step(int n) {
setProgress(progress + n);
return progress;
}
- /**
- * Sets the maximum value of the progress bar.
- * @throws IllegalArgumentException If {@code maximum < minimum}
- */
public void setMaximum(int maximum) {
if (maximum < minimum) {
throw new IllegalArgumentException("maximum may not be less than minimum");
@@ -102,18 +75,10 @@ public void setMaximum(int maximum) {
LoadingScreenApi.customProgressBarOp(id, "maximum", Integer.toString(maximum));
}
- /**
- * Gets the maximum value of the progress bar.
- */
public int getMaximum() {
return maximum;
}
-
- /**
- * Sets the minimum value of the progress bar.
- * @throws IllegalArgumentException If {@code minimum > maximum}
- */
public void setMinimum(int minimum) {
if (minimum > maximum) {
throw new IllegalArgumentException("minimum may not be greater than maximum");
@@ -124,36 +89,34 @@ public void setMinimum(int minimum) {
LoadingScreenApi.customProgressBarOp(id, "minimum", Integer.toString(minimum));
}
-
- /**
- * Gets the minimum value of the progress bar.
- */
public int getMinimum() {
return minimum;
}
- /**
- * Sets the display text of the progress bar.
- */
- public void setTitle(String title) {
- Objects.requireNonNull(title, "title");
+ public void setTitle(String titleKey, String... titleArgs) {
+ Objects.requireNonNull(titleKey, "titleKey");
checkClosed();
- if (title.equals(this.title)) return;
- this.title = title;
- LoadingScreenApi.customProgressBarOp(id, "title", title);
+ this.titleKey = titleKey;
+ this.titleArgs = titleArgs != null ? titleArgs : new String[0];
+ if (this.titleArgs.length > 0) {
+ String[] opArgs = new String[this.titleArgs.length + 2];
+ opArgs[0] = "title";
+ opArgs[1] = titleKey;
+ System.arraycopy(this.titleArgs, 0, opArgs, 2, this.titleArgs.length);
+ LoadingScreenApi.customProgressBarOp(id, opArgs);
+ } else {
+ LoadingScreenApi.customProgressBarOp(id, "title", titleKey);
+ }
+ }
+
+ public String getTitleKey() {
+ return titleKey;
}
- /**
- * Gets the display text of the progress bar.
- */
- public String getTitle() {
- return title;
+ public String[] getTitleArgs() {
+ return titleArgs.clone();
}
- /**
- * Sets whether the progress bar is indeterminate. If the progress bar is indeterminate, {@link #setProgress} will
- * still take effect, but it won't be visible until the progress bar is determinate.
- */
public void setIndeterminate(boolean indeterminate) {
checkClosed();
if (indeterminate == this.indeterminate) return;
@@ -161,17 +124,10 @@ public void setIndeterminate(boolean indeterminate) {
LoadingScreenApi.customProgressBarOp(id, "indeterminate", Boolean.toString(indeterminate));
}
- /**
- * Returns whether the progress bar is currently indeterminate.
- */
public boolean isIndeterminate() {
return indeterminate;
}
- /**
- * Returns whether the progress bar is a real progress bar that can show up. This returns {@code true} if a version
- * of Mod Loading Screen that supports custom progress bars is installed.
- */
public boolean isReal() {
return isReal;
}
From e7a95c2de88d6c580815afc6f03441f804bc4a44 Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 09:13:13 +0800
Subject: [PATCH 03/26] Refactor LoadingScreenApi to support custom titles
---
.../api/LoadingScreenApi.java | 155 +++---------------
1 file changed, 27 insertions(+), 128 deletions(-)
diff --git a/src/api/java/io/github/gaming32/modloadingscreen/api/LoadingScreenApi.java b/src/api/java/io/github/gaming32/modloadingscreen/api/LoadingScreenApi.java
index b82a001..2a3914a 100644
--- a/src/api/java/io/github/gaming32/modloadingscreen/api/LoadingScreenApi.java
+++ b/src/api/java/io/github/gaming32/modloadingscreen/api/LoadingScreenApi.java
@@ -85,7 +85,7 @@ public final class LoadingScreenApi {
try {
createCustomProgressBar = lookup.findStatic(
alsClass, "createCustomProgressBar",
- MethodType.methodType(void.class, String.class, String.class, int.class)
+ MethodType.methodType(void.class, String.class, String.class, int.class, String[].class)
);
customProgressBarOp = lookup.findStatic(
alsClass, "customProgressBarOp",
@@ -93,8 +93,20 @@ public final class LoadingScreenApi {
);
features |= AvailableFeatures.CUSTOM_PROGRESS_BARS;
} catch (Exception e) {
- createCustomProgressBar = null;
- loadFailed(">=1.0.4", AvailableFeatures.CUSTOM_PROGRESS_BARS, e);
+ try {
+ createCustomProgressBar = lookup.findStatic(
+ alsClass, "createCustomProgressBar",
+ MethodType.methodType(void.class, String.class, String.class, int.class)
+ );
+ customProgressBarOp = lookup.findStatic(
+ alsClass, "customProgressBarOp",
+ MethodType.methodType(void.class, String[].class)
+ );
+ features |= AvailableFeatures.CUSTOM_PROGRESS_BARS;
+ } catch (Exception ex) {
+ createCustomProgressBar = null;
+ loadFailed(">=1.0.4", AvailableFeatures.CUSTOM_PROGRESS_BARS, ex);
+ }
}
System.out.println("[ModLoadingScreen] API loaded with features: " + AvailableFeatures.toString(features));
@@ -104,8 +116,6 @@ public final class LoadingScreenApi {
System.err.println(message);
e.printStackTrace();
} else {
- // This API could be called with Mod Loading Screen simply absent, in which case this is *not* an error
- // condition
System.out.println(message);
System.out.println("[ModLoadingScreen] This is not an error, because Mod Loading Screen is not installed.");
}
@@ -159,40 +169,14 @@ private static void loadFailed(String mlsVersionRequired, long feature, Exceptio
private LoadingScreenApi() {
}
- /**
- * Returns the features of the API that are available to use, as a bit mask of flags from
- * {@link AvailableFeatures}. Any features not available will default to no-op fallback implementations.
- *
- * @see AvailableFeatures
- */
public static long getFeatures() {
return FEATURES;
}
- /**
- * Returns whether the bitmask of features is supported.
- *
- * @param requestedFeatures A bitmask of feature flags from {@link AvailableFeatures}
- *
- * @return Whether all the requested features are available
- *
- * @see AvailableFeatures
- * @see AvailableFeatures#hasFeatures
- */
public static boolean hasFeatures(long requestedFeatures) {
return AvailableFeatures.hasFeatures(FEATURES, requestedFeatures);
}
- /**
- * Invokes an entrypoint with a clean API. If Mod Loading Screen is available, its progress will show up in the
- * loading screen.
- *
- * @throws RuntimeException If any entrypoints threw an exception
- *
- * @apiNote This feature is always available, regardless of the return value of {@link #getFeatures}.
- * Calling this without Mod Loading Screen will work always, but just won't show up in the (non-existent) loading
- * screen.
- */
public static void invokeEntrypoint(String name, Class type, Consumer super T> invoker) throws RuntimeException {
if (FABRIC_0_14_23_INVOKE_ENTRYPOINTS != null) {
try {
@@ -205,9 +189,6 @@ public static void invokeEntrypoint(String name, Class type, Consumer s
try {
EntrypointUtils.invoke(name, type, invoker);
} catch (RuntimeException e) {
- // Quilt bug! Quilt's EntrypointExceptions are never converted to Fabric's!
- // https://github.com/QuiltMC/quilt-loader/issues/366
- // Fixed in Quilt since 0.21.0-beta.4. Fix kept for backwards compat.
Class> clazz = e.getClass();
while (clazz != null) {
if (clazz.getName().equals("org.quiltmc.loader.api.entrypoint.EntrypointException")) {
@@ -224,21 +205,6 @@ public static void invokeEntrypoint(String name, Class type, Consumer s
}
}
- /**
- * Returns a set of "final entrypoint" names. "Final entrypoints" are entrypoints that, when finished invoking,
- * will close the loading screen. You can use the return value to add or remove entrypoints so that they don't
- * exit the loading screen, and you can add your own entrypoints that should close the loading screen instead. Be
- * careful about mod compatibility when using this!
- *
- * @apiNote If {@link #getFeatures} doesn't include {@link AvailableFeatures#FINAL_ENTRYPOINTS}, this will return
- * an empty {@link Set} that does nothing when modified, and changes to it will not be seen by other mods.
- *
- * @return The mutable set of "final entrypoints".
- *
- * @see AvailableFeatures#FINAL_ENTRYPOINTS
- *
- * @since 1.0.3
- */
@SuppressWarnings("unchecked")
public static Set getFinalEntrypoints() {
if (FINAL_ENTRYPOINTS == null) {
@@ -251,18 +217,6 @@ public static Set getFinalEntrypoints() {
}
}
- /**
- * Returns whether the Mod Loading Screen (and the game in general) is running in a headless environment. If
- * {@link #getFeatures} doesn't include {@link AvailableFeatures#HEADLESS_CHECK}, this will return the value of
- * {@link GraphicsEnvironment#isHeadless}.
- *
- * @return {@code true} if running in a headless environment.
- *
- * @see GraphicsEnvironment#isHeadless
- * @see AvailableFeatures#HEADLESS_CHECK
- *
- * @since 1.0.3
- */
public static boolean isHeadless() {
if (IS_HEADLESS == null) {
return GraphicsEnvironment.isHeadless();
@@ -274,21 +228,6 @@ public static boolean isHeadless() {
}
}
- /**
- * Returns whether IPC is being used for the loading screen, and hasn't been disabled with
- * {@code mod-loading-screen.disableIpc}. If {@link #isHeadless} returns {@code true}, this will return
- * {@code false}. If {@link #getFeatures} doesn't include {@link AvailableFeatures#IPC_CHECK}, this will return
- * {@code false}.
- *
- * @return {@code true} IPC is being used for the loading screen.
- *
- * @deprecated Non-IPC may be removed in the future, at which point this will always return the opposite of
- * {@link #isHeadless}
- *
- * @see AvailableFeatures#IPC_CHECK
- *
- * @since 1.0.3
- */
@Deprecated
public static boolean isUsingIpc() {
if (ENABLE_IPC == null) {
@@ -313,54 +252,17 @@ private static Map getAllProgress() {
}
}
- /**
- * Returns an {@link Set} of progress bar names. This will be updated dynamically when bars are updated. If
- * {@link #getFeatures} doesn't include {@link AvailableFeatures#GET_PROGRESS}, this will return an empty set.
- *
- * @apiNote Custom progress bars start with {@code "custom:"}, followed by their ID. If {@link #getFeatures}
- * includes {@link AvailableFeatures#CUSTOM_PROGRESS_BARS}, entrypoint progress bars start with
- * {@code "entrypoint:"}
- *
- * @see AvailableFeatures#GET_PROGRESS
- *
- * @since 1.0.3
- */
@UnmodifiableView
public static Set getActiveProgressBars() {
final Set bars = getAllProgress().keySet();
return bars == Collections.EMPTY_SET ? bars : Collections.unmodifiableSet(bars);
}
- /**
- * Returns the current progress of a progress bar, or {@code null} if there is no such progress bar. If
- * {@link #getFeatures} doesn't include {@link AvailableFeatures#GET_PROGRESS}, this will always return
- * {@code null}.
- *
- * @param barName The name of the progress bar. In the case of entrypoints, this is the name of the entrypoint.
- *
- * @apiNote Custom progress bars start with {@code "custom:"}, followed by their ID. If {@link #getFeatures}
- * includes {@link AvailableFeatures#CUSTOM_PROGRESS_BARS}, entrypoint progress bars start with
- * {@code "entrypoint:"}
- *
- * @see AvailableFeatures#GET_PROGRESS
- *
- * @since 1.0.3
- */
@Nullable
public static Integer getProgress(@NotNull String barName) {
return getAllProgress().get(barName);
}
- /**
- * Returns whether a loading screen is currently active. If {@link #getFeatures} doesn't include
- * {@link AvailableFeatures#OPEN_CHECK}, this will always return {@code false}.
- *
- * @return {@code true} if there is a loading screen open.
- *
- * @see AvailableFeatures#OPEN_CHECK
- *
- * @since 1.0.3
- */
public static boolean isOpen() {
if (IS_OPEN == null) {
return false;
@@ -372,35 +274,32 @@ public static boolean isOpen() {
}
}
- /**
- * Creates a custom progress bar.
- * @param title The title of the progress bar. This is the full string to display.
- * @param max The maximum value of the progress bar. It will not be removed automatically when this is
- * reached.
- * @return The {@link CustomProgressBar} reference to the progress bar.
- */
- public static CustomProgressBar getCustomProgressBar(@NotNull String id, @NotNull String title, int max) {
+ public static CustomProgressBar getCustomProgressBar(@NotNull String id, @NotNull String titleKey, int max, String... titleArgs) {
CustomProgressBar bar = CUSTOM_PROGRESS_BARS.get(id);
if (bar == null) {
- CUSTOM_PROGRESS_BARS.put(id, bar = createCustomProgressBar(id, title, max));
+ CUSTOM_PROGRESS_BARS.put(id, bar = createCustomProgressBar(id, titleKey, max, titleArgs));
}
- bar.setTitle(title);
+ bar.setTitle(titleKey, titleArgs);
bar.setMaximum(max);
return bar;
}
- private static CustomProgressBar createCustomProgressBar(String id, String title, int max) {
+ private static CustomProgressBar createCustomProgressBar(String id, String titleKey, int max, String... titleArgs) {
Objects.requireNonNull(id, "id");
- Objects.requireNonNull(title, "title");
+ Objects.requireNonNull(titleKey, "titleKey");
if (CREATE_CUSTOM_PROGRESS_BAR == null) {
- return new CustomProgressBar(id, false, title, max);
+ return new CustomProgressBar(id, false, titleKey, max, titleArgs);
}
try {
- CREATE_CUSTOM_PROGRESS_BAR.invokeExact(id, title, max);
+ if (CREATE_CUSTOM_PROGRESS_BAR.type().parameterCount() == 4) {
+ CREATE_CUSTOM_PROGRESS_BAR.invokeExact(id, titleKey, max, titleArgs != null ? titleArgs : new String[0]);
+ } else {
+ CREATE_CUSTOM_PROGRESS_BAR.invokeExact(id, titleKey, max);
+ }
} catch (Throwable t) {
rethrow(t);
}
- return new CustomProgressBar(id, true, title, max);
+ return new CustomProgressBar(id, true, titleKey, max, titleArgs);
}
static void customProgressBarOp(String... args) {
From 36315d36627a82c757eca0901cd86e91886fdad8 Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 09:14:31 +0800
Subject: [PATCH 04/26] Implement translation loading and progress bar updates
Added translation support for loading screen messages and improved progress bar title handling.
---
.../modloadingscreen/ActualLoadingScreen.java | 98 +++++++++++++++----
1 file changed, 79 insertions(+), 19 deletions(-)
diff --git a/src/main/java/io/github/gaming32/modloadingscreen/ActualLoadingScreen.java b/src/main/java/io/github/gaming32/modloadingscreen/ActualLoadingScreen.java
index 8c5a56b..51c489c 100644
--- a/src/main/java/io/github/gaming32/modloadingscreen/ActualLoadingScreen.java
+++ b/src/main/java/io/github/gaming32/modloadingscreen/ActualLoadingScreen.java
@@ -13,27 +13,35 @@
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GraphicsEnvironment;
+import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.MalformedURLException;
import java.net.URL;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
+import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
+import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import static io.github.gaming32.modloadingscreen.MlsTransformers.ACTUAL_LOADING_SCREEN;
@@ -48,7 +56,6 @@ public class ActualLoadingScreen {
!IS_IPC_CLIENT && !IS_HEADLESS && !Boolean.getBoolean("mod-loading-screen.disableIpc");
public static final String[] SUPPORTED_BACKGROUND_FORMATS = {"gif", "jpeg", "png", "xbm"};
- // Unlike progressBars, this is populated on both the IPC client and IPC server, allowing it to be used from the API
public static final Map progress = new LinkedHashMap<>();
private static final Map progressBars = new LinkedHashMap<>();
private static JFrame dialog;
@@ -59,12 +66,58 @@ public class ActualLoadingScreen {
private static Thread memoryThread;
private static boolean titleSet;
- static boolean runningOnQuilt; // Accessed from EarlyLoadingAgent
+ static boolean runningOnQuilt;
private static Path configDir;
private static boolean enableMemoryDisplay = true;
+ private static final Map TRANSLATIONS = new HashMap<>();
+
+ public static void loadTranslations() {
+ TRANSLATIONS.clear();
+ loadLangFile("en_us");
+ final String locale = Locale.getDefault().toString().toLowerCase(Locale.ROOT);
+ if (!locale.equals("en_us")) {
+ loadLangFile(locale);
+ }
+ }
+
+ private static void loadLangFile(String langCode) {
+ final InputStream is = ClassLoader.getSystemResourceAsStream("assets/mod-loading-screen/lang/" + langCode + ".json");
+ if (is == null) return;
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
+ final Pattern pattern = Pattern.compile("^\\s*\"([^\"]+)\"\\s*:\\s*\"(.*)\",?\\s*$");
+ String line;
+ while ((line = reader.readLine()) != null) {
+ final Matcher matcher = pattern.matcher(line);
+ if (matcher.matches()) {
+ String val = matcher.group(2).replace("\\\"", "\"").replace("\\\\", "\\").replace("\\n", "\n");
+ TRANSLATIONS.put(matcher.group(1), val);
+ }
+ }
+ } catch (Exception ignored) {
+ }
+ }
+
+ public static String translate(String key, Object... args) {
+ String pattern = TRANSLATIONS.getOrDefault(key, key);
+ if (args == null || args.length == 0) {
+ return pattern;
+ }
+ try {
+ return String.format(pattern, args);
+ } catch (Exception e) {
+ try {
+ return MessageFormat.format(pattern, args);
+ } catch (Exception ex) {
+ return pattern;
+ }
+ }
+ }
+
public static void startLoadingScreen(boolean fabricReady) {
+ loadTranslations();
+
final Path gameDir = fabricReady ? FabricLoader.getInstance().getGameDir() : Paths.get(".").toAbsolutePath();
final Path runDir = gameDir.resolve(".cache/mod-loading-screen");
@@ -95,7 +148,6 @@ public static void startLoadingScreen(boolean fabricReady) {
runningOnQuilt = FabricLoader.getInstance().isModLoaded("quilt_loader");
configDir = FabricLoader.getInstance().getConfigDir().resolve("mod-loading-screen");
} else {
- // This code is certainly something. I don't have any ideas for improvement, though.
runningOnQuilt = System.getProperty("java.class.path").contains("quilt-loader");
configDir = Paths.get("config/mod-loading-screen").toAbsolutePath();
}
@@ -176,7 +228,7 @@ public static void startLoadingScreen(boolean fabricReady) {
if (fabricReady) {
setFabricTitle();
} else {
- dialog.setTitle(runningOnQuilt ? "Loading Quilt Loader" : "Loading Fabric Loader");
+ dialog.setTitle(translate(runningOnQuilt ? "modloadingscreen.title.loading_quilt" : "modloadingscreen.title.loading_fabric"));
}
dialog.setResizable(false);
@@ -279,7 +331,7 @@ private static void startMemoryThread() {
public static void setTitleFromMetadata(String id, String name, String version) {
if (titleSet || IGNORED_BUILTIN.contains(id)) return;
titleSet = true;
- setTitle("Loading " + name + ' ' + version);
+ setTitle(translate("modloadingscreen.title.loading_mod", name, version));
}
private static void setFabricTitle() {
@@ -378,16 +430,21 @@ public static void maybeCloseAfter(String type) {
close();
}
- public static void createCustomProgressBar(String id, String title, int max) {
+ public static void createCustomProgressBar(String id, String titleKey, int max, String... titleArgs) {
final String fullId = "custom:" + id;
progress.put(fullId, 0);
- if (sendIpc(4, id, title, Integer.toString(max))) return;
+ String[] ipcArgs = new String[titleArgs.length + 3];
+ ipcArgs[0] = id;
+ ipcArgs[1] = titleKey;
+ ipcArgs[2] = Integer.toString(max);
+ System.arraycopy(titleArgs, 0, ipcArgs, 3, titleArgs.length);
+ if (sendIpc(4, ipcArgs)) return;
if (dialog == null) return;
final JProgressBar progressBar = new JProgressBar(0, max);
progressBar.setStringPainted(true);
- progressBar.setString(title);
+ progressBar.setString(translate(titleKey, (Object[]) titleArgs));
progressBars.put(fullId, progressBar);
label.add(progressBar, BorderLayout.SOUTH, 1);
label.revalidate();
@@ -427,7 +484,9 @@ public static void customProgressBarOp(String... args) {
progressBar.setMinimum(Integer.parseInt(args[2]));
break;
case "title":
- progressBar.setString(args[2]);
+ String[] formatArgs = new String[args.length - 3];
+ System.arraycopy(args, 3, formatArgs, 0, formatArgs.length);
+ progressBar.setString(translate(args[2], (Object[]) formatArgs));
break;
case "indeterminate":
progressBar.setIndeterminate(Boolean.parseBoolean(args[2]));
@@ -488,17 +547,17 @@ private static void updateMemoryUsage0(long usage, long total) {
memoryBar.setMaximum(totalMb);
memoryBar.setValue(usageMb);
- memoryBar.setString(usageMb + " MB / " + totalMb + " MB");
+ memoryBar.setString(translate("modloadingscreen.memory.usage", usageMb, totalMb));
}
private static void setLabel(JProgressBar progressBar, String typeName, String typeType, @Nullable String modName) {
- final StringBuilder message = new StringBuilder("Loading '").append(typeName)
- .append("' (").append(typeType).append(") \u2014 ")
- .append(progressBar.getValue()).append('/').append(progressBar.getMaximum());
+ final int current = progressBar.getValue();
+ final int max = progressBar.getMaximum();
if (modName != null) {
- message.append(" \u2014 ").append(modName);
+ progressBar.setString(translate("modloadingscreen.entrypoint.status_mod", typeName, typeType, current, max, modName));
+ } else {
+ progressBar.setString(translate("modloadingscreen.entrypoint.status", typeName, typeType, current, max));
}
- progressBar.setString(message.toString());
}
private static void println(String message) {
@@ -549,7 +608,6 @@ private static boolean sendIpc(int id, String... args) {
return true;
}
- // IPC client
public static void main(String[] args) {
try {
logFile = new PrintStream("ipc-client-log.txt");
@@ -576,7 +634,9 @@ public static void main(String[] args) {
updateMemoryUsage0(Long.parseLong(packetArgs[0]), Long.parseLong(packetArgs[1]));
break;
case 4:
- createCustomProgressBar(packetArgs[0], packetArgs[1], Integer.parseInt(packetArgs[2]));
+ String[] createArgs = new String[packetArgs.length - 3];
+ System.arraycopy(packetArgs, 3, createArgs, 0, createArgs.length);
+ createCustomProgressBar(packetArgs[0], packetArgs[1], Integer.parseInt(packetArgs[2]), createArgs);
break;
case 5:
customProgressBarOp(packetArgs);
@@ -592,8 +652,8 @@ public static void main(String[] args) {
} catch (Exception e) {
println("Error in IPC client", e);
JOptionPane.showMessageDialog(
- dialog, "An error occurred in Mod Loading Screen's IPC client\n" + e,
- "Mod Loading Screen IPC Client", JOptionPane.ERROR_MESSAGE
+ dialog, translate("modloadingscreen.error.ipc_client", e),
+ translate("modloadingscreen.error.ipc_client_title"), JOptionPane.ERROR_MESSAGE
);
}
close();
From eec6d4ca7f79ef2b29e2c1f2b8860bb4e3421b91 Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 09:15:11 +0800
Subject: [PATCH 05/26] Replace print statements with translation calls
---
.../github/gaming32/modloadingscreen/EarlyLoadingAgent.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/main/java/io/github/gaming32/modloadingscreen/EarlyLoadingAgent.java b/src/main/java/io/github/gaming32/modloadingscreen/EarlyLoadingAgent.java
index 06fd58b..e3f8d33 100644
--- a/src/main/java/io/github/gaming32/modloadingscreen/EarlyLoadingAgent.java
+++ b/src/main/java/io/github/gaming32/modloadingscreen/EarlyLoadingAgent.java
@@ -11,19 +11,19 @@
public class EarlyLoadingAgent {
public static void premain(String args, Instrumentation instrumentation) throws IOException {
- System.out.println("[ModLoadingScreen] I just want to say... I'm loading *really* **extremely** early.");
+ System.out.println(ActualLoadingScreen.translate("modloadingscreen.log.early_loading"));
System.setProperty("mod-loading-screen.loaded", "true");
final Path flatlafDestPath = Paths.get(".cache/mod-loading-screen/flatlaf.jar").toAbsolutePath();
Files.createDirectories(flatlafDestPath.getParent());
try (InputStream is = EarlyLoadingAgent.class.getClassLoader().getResourceAsStream(MlsConstants.FLATLAF_PATH)) {
if (is == null) {
- System.err.println("[ModLoadingScreen] [ERROR] flatlaf.jar not found! Aborting.");
+ System.err.println(ActualLoadingScreen.translate("modloadingscreen.log.flatlaf_not_found"));
return;
}
Files.copy(is, flatlafDestPath, StandardCopyOption.REPLACE_EXISTING);
}
- System.out.println("[ModLoadingScreen] Extracted flatlaf.jar");
+ System.out.println(ActualLoadingScreen.translate("modloadingscreen.log.extracted_flatlaf"));
instrumentation.appendToSystemClassLoaderSearch(new JarFile(flatlafDestPath.toFile()));
ActualLoadingScreen.startLoadingScreen(false);
From 4fe79a5afc99a8efc65bd835fd91a9e74e1ce321 Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 09:16:03 +0800
Subject: [PATCH 06/26] Update FLATLAF_PATH to point to flatlaf-3.5.4.jar
From 1b4b420c8feb42c20b9a24311f3b87dc5aa68dfd Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 09:17:16 +0800
Subject: [PATCH 07/26] Replace console logs with translation method calls
---
.../modloadingscreen/MlsTransformers.java | 44 ++++---------------
1 file changed, 8 insertions(+), 36 deletions(-)
diff --git a/src/main/java/io/github/gaming32/modloadingscreen/MlsTransformers.java b/src/main/java/io/github/gaming32/modloadingscreen/MlsTransformers.java
index 5f37e3f..4ddfa10 100644
--- a/src/main/java/io/github/gaming32/modloadingscreen/MlsTransformers.java
+++ b/src/main/java/io/github/gaming32/modloadingscreen/MlsTransformers.java
@@ -74,7 +74,7 @@ static byte[] instrumentClass(String name, byte[] bytes) {
synchronized (MlsTransformers.class) {
if (!notifiedClassDump) {
notifiedClassDump = true;
- System.out.println("[ModLoadingScreen] Transformed class dumping is active");
+ System.out.println(ActualLoadingScreen.translate("modloadingscreen.log.dump_active"));
try {
final Path dumpDir = Paths.get(".mlsDebugDump");
if (Files.isDirectory(dumpDir)) {
@@ -93,7 +93,7 @@ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOEx
});
}
} catch (Throwable t) {
- System.err.println("[ModLoadingScreen] [ERROR] Failed to clear debug dump dir");
+ System.err.println(ActualLoadingScreen.translate("modloadingscreen.log.dump_clear_failed"));
}
}
}
@@ -102,7 +102,7 @@ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOEx
try {
final Collection> transformer = TRANSFORMERS.get(name);
if (transformer != null) {
- System.out.println("[ModLoadingScreen] Transforming " + name);
+ System.out.println(ActualLoadingScreen.translate("modloadingscreen.log.transforming", name));
final ClassReader reader = new ClassReader(bytes);
final ClassNode clazz = new ClassNode();
reader.accept(clazz, 0);
@@ -110,7 +110,7 @@ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOEx
try {
part.accept(clazz);
} catch (Exception e) {
- System.err.println("[ModLoadingScreen] [ERROR] Transformer " + part + " for " + name + " failed");
+ System.err.println(ActualLoadingScreen.translate("modloadingscreen.log.transformer_failed", part, name));
e.printStackTrace();
}
}
@@ -123,14 +123,14 @@ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOEx
Files.createDirectories(dumpedPath.getParent());
Files.write(dumpedPath, result);
} catch (Exception e) {
- System.err.println("[ModLoadingScreen] [ERROR] Failed to dump class " + name);
+ System.err.println(ActualLoadingScreen.translate("modloadingscreen.log.dump_failed", name));
e.printStackTrace();
}
}
return result;
}
} catch (Throwable t) {
- System.err.println("[ModLoadingScreen] [ERROR] Completely failed to transform " + name);
+ System.err.println(ActualLoadingScreen.translate("modloadingscreen.log.transform_failed", name));
t.printStackTrace();
}
return null;
@@ -142,7 +142,7 @@ private static void instrumentFabricLoaderImplInvokeEntrypoints(ClassNode clazz)
.findFirst()
.orElse(null);
if (method == null) {
- System.out.println("[ModLoadingScreen] New-style FabricLoaderImpl.invokeEntrypoints not found. Assuming old Fabric.");
+ System.out.println(ActualLoadingScreen.translate("modloadingscreen.log.old_fabric_fallback"));
return;
}
final ListIterator it = method.instructions.iterator();
@@ -155,7 +155,7 @@ private static void instrumentFabricLoaderImplInvokeEntrypoints(ClassNode clazz)
if (insn.getOpcode() == Opcodes.ACONST_NULL) break;
}
it.previous();
- mainEntrypointHooks(it, false, true);
+ mainEntrypointHooks(it, false, true);
maybeCloseAfter(it, true);
}
@@ -170,9 +170,6 @@ private static void instrumentEntrypointUtilsInvoke(ClassNode clazz, boolean onQ
maybeCloseAfter(it, false);
}
- /**
- * Inserts code for calling maybeCloseAfter, and leaves {@code it} pointing to the {@code RETURN}.
- */
private static void maybeCloseAfter(ListIterator it, boolean instanceMethod) {
while (it.hasNext()) {
final AbstractInsnNode insn = it.next();
@@ -201,7 +198,6 @@ private static void instrumentEntrypointUtilsInvoke0(ClassNode clazz, boolean on
private static void mainEntrypointHooks(ListIterator it, boolean onQuilt, boolean instanceMethod) {
final int varOffset = instanceMethod ? 1 : 0;
- //noinspection PointlessArithmeticExpression
final int keyIndex = 0 + varOffset;
final int typeIndex = 1 + varOffset;
@@ -297,32 +293,20 @@ private static void instrumentModDiscovererDiscoverMods(ClassNode clazz, boolean
if (insn.getOpcode() == Opcodes.CHECKCAST && ((TypeInsnNode)insn).desc.equals(BuiltinMod)) break;
}
- // BuiltinMod
it.add(new InsnNode(Opcodes.DUP));
- // BuiltinMod BuiltinMod
it.add(new FieldInsnNode(Opcodes.GETFIELD, BuiltinMod, "metadata", "L" + MOD_METADATA + ";"));
- // BuiltinMod ModMetadata
it.add(new InsnNode(Opcodes.DUP));
- // BuiltinMod ModMetadata ModMetadata
it.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE, MOD_METADATA, "getId", "()Ljava/lang/String;"));
- // BuiltinMod ModMetadata String
it.add(new InsnNode(Opcodes.SWAP));
- // BuiltinMod String ModMetadata
it.add(new InsnNode(Opcodes.DUP));
- // BuiltinMod String ModMetadata ModMetadata
it.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE, MOD_METADATA, "getName", "()Ljava/lang/String;"));
- // BuiltinMod String ModMetadata String
it.add(new InsnNode(Opcodes.SWAP));
- // BuiltinMod String String ModMetadata
it.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE, MOD_METADATA, "getVersion", "()L" + FABRIC_VERSION + ";"));
- // BuiltinMod String String Version
it.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE, FABRIC_VERSION, "getFriendlyString", "()Ljava/lang/String;"));
- // BuiltinMod String String String
it.add(new MethodInsnNode(
Opcodes.INVOKESTATIC, ACTUAL_LOADING_SCREEN, "setTitleFromMetadata",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"
));
- // BuiltinMod
}
private static void instrumentStandardQuiltPluginAddBuiltinMods(ClassNode clazz) {
@@ -338,31 +322,19 @@ private static void instrumentStandardQuiltPluginAddBuiltinMods(ClassNode clazz)
if (insn.getOpcode() == Opcodes.CHECKCAST && ((TypeInsnNode)insn).desc.equals(QUILT_BUILTIN_MOD)) break;
}
- // BuiltinMod
it.add(new InsnNode(Opcodes.DUP));
- // BuiltinMod BuiltinMod
it.add(new FieldInsnNode(Opcodes.GETFIELD, QUILT_BUILTIN_MOD, "metadata", "L" + INTERNAL_MOD_METADATA + ";"));
- // BuiltinMod InternalModMetadata
it.add(new InsnNode(Opcodes.DUP));
- // BuiltinMod InternalModMetadata InternalModMetadata
it.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE, INTERNAL_MOD_METADATA, "id", "()Ljava/lang/String;"));
- // BuiltinMod InternalModMetadata String
it.add(new InsnNode(Opcodes.SWAP));
- // BuiltinMod String InternalModMetadata
it.add(new InsnNode(Opcodes.DUP));
- // BuiltinMod String InternalModMetadata InternalModMetadata
it.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE, INTERNAL_MOD_METADATA, "name", "()Ljava/lang/String;"));
- // BuiltinMod String InternalModMetadata String
it.add(new InsnNode(Opcodes.SWAP));
- // BuiltinMod String String InternalModMetadata
it.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE, INTERNAL_MOD_METADATA, "version", "()L" + QUILT_VERSION + ";"));
- // BuiltinMod String String Version
it.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE, QUILT_VERSION, "raw", "()Ljava/lang/String;"));
- // BuiltinMod String String String
it.add(new MethodInsnNode(
Opcodes.INVOKESTATIC, ACTUAL_LOADING_SCREEN, "setTitleFromMetadata",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"
));
- // BuiltinMod
}
}
From 7df70f33a026db30d8fdafe4d0f7161699e43ab9 Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 09:18:03 +0800
Subject: [PATCH 08/26] Replace hardcoded strings with translation calls
---
.../gaming32/modloadingscreen/ModLoadingScreen.java | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/main/java/io/github/gaming32/modloadingscreen/ModLoadingScreen.java b/src/main/java/io/github/gaming32/modloadingscreen/ModLoadingScreen.java
index 68700fd..f0c4c94 100644
--- a/src/main/java/io/github/gaming32/modloadingscreen/ModLoadingScreen.java
+++ b/src/main/java/io/github/gaming32/modloadingscreen/ModLoadingScreen.java
@@ -27,16 +27,16 @@ public class ModLoadingScreen implements LanguageAdapter {
@SuppressWarnings("unchecked")
public T create(ModContainer mod, String value, Class type) throws LanguageAdapterException {
if (type != PreLaunchEntrypoint.class) {
- throw new LanguageAdapterException("Fake entrypoint only supported on PreLaunchEntrypoint");
+ throw new LanguageAdapterException(ActualLoadingScreen.translate("modloadingscreen.error.fake_entrypoint_unsupported"));
}
return (T)(PreLaunchEntrypoint)() -> {};
}
public static void init() throws Throwable {
- System.out.println("[ModLoadingScreen] I just want to say... I'm loading *really* early.");
+ System.out.println(ActualLoadingScreen.translate("modloadingscreen.log.mod_loading_early"));
if (System.setProperty("mod-loading-screen.loaded", "true") != null) {
- System.err.println("[ModLoadingScreen] [WARN] Mod Loading Screen installed as both a mod and an agent.");
- System.err.println("[ModLoadingScreen] [WARN] Please avoid doing this. To avoid issues, the mod has disabled itself.");
+ System.err.println(ActualLoadingScreen.translate("modloadingscreen.log.dual_install_warn1"));
+ System.err.println(ActualLoadingScreen.translate("modloadingscreen.log.dual_install_warn2"));
return;
}
@@ -87,7 +87,7 @@ public static void init() throws Throwable {
try {
init();
} catch (Throwable t) {
- System.err.println("[ModLoadingScreen] Failed to initialize loading screen. Aborting!");
+ System.err.println(ActualLoadingScreen.translate("modloadingscreen.log.init_failed"));
throw new Error(t);
}
}
From 73b2629fdcea2e169320b17a6cfb2c8879aa8baa Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 09:19:12 +0800
Subject: [PATCH 09/26] Add English localization for mod loading screen
---
.../assets/mod-loading-screen/en_us.json | 37 +++++++++++++++++++
1 file changed, 37 insertions(+)
create mode 100644 src/main/resources/assets/mod-loading-screen/en_us.json
diff --git a/src/main/resources/assets/mod-loading-screen/en_us.json b/src/main/resources/assets/mod-loading-screen/en_us.json
new file mode 100644
index 0000000..d8a1ce2
--- /dev/null
+++ b/src/main/resources/assets/mod-loading-screen/en_us.json
@@ -0,0 +1,37 @@
+{
+ "modloadingscreen.feature.final_entrypoints": "Final Entrypoints",
+ "modloadingscreen.feature.headless_check": "Headless Check",
+ "modloadingscreen.feature.ipc_check": "IPC Check",
+ "modloadingscreen.feature.get_progress": "Get Progress",
+ "modloadingscreen.feature.open_check": "Open Check",
+ "modloadingscreen.feature.custom_progress_bars": "Custom Progress Bars",
+ "modloadingscreen.feature.unknown": "Unknown Feature",
+
+ "modloadingscreen.title.loading_quilt": "Loading Quilt Loader",
+ "modloadingscreen.title.loading_fabric": "Loading Fabric Loader",
+ "modloadingscreen.title.loading_mod": "Loading %s %s",
+
+ "modloadingscreen.memory.usage": "%d MB / %d MB",
+
+ "modloadingscreen.entrypoint.status": "Loading '%s' (%s) \u2014 %d/%d",
+ "modloadingscreen.entrypoint.status_mod": "Loading '%s' (%s) \u2014 %d/%d \u2014 %s",
+
+ "modloadingscreen.error.ipc_client": "An error occurred in Mod Loading Screen's IPC client\n%s",
+ "modloadingscreen.error.ipc_client_title": "Mod Loading Screen IPC Client",
+ "modloadingscreen.error.fake_entrypoint_unsupported": "Fake entrypoint only supported on PreLaunchEntrypoint",
+
+ "modloadingscreen.log.early_loading": "[ModLoadingScreen] I just want to say... I'm loading *really* **extremely** early.",
+ "modloadingscreen.log.flatlaf_not_found": "[ModLoadingScreen] [ERROR] flatlaf.jar not found! Aborting.",
+ "modloadingscreen.log.extracted_flatlaf": "[ModLoadingScreen] Extracted flatlaf.jar",
+ "modloadingscreen.log.dump_active": "[ModLoadingScreen] Transformed class dumping is active",
+ "modloadingscreen.log.dump_clear_failed": "[ModLoadingScreen] [ERROR] Failed to clear debug dump dir",
+ "modloadingscreen.log.transforming": "[ModLoadingScreen] Transforming %s",
+ "modloadingscreen.log.transformer_failed": "[ModLoadingScreen] [ERROR] Transformer %s for %s failed",
+ "modloadingscreen.log.dump_failed": "[ModLoadingScreen] [ERROR] Failed to dump class %s",
+ "modloadingscreen.log.transform_failed": "[ModLoadingScreen] [ERROR] Completely failed to transform %s",
+ "modloadingscreen.log.old_fabric_fallback": "[ModLoadingScreen] New-style FabricLoaderImpl.invokeEntrypoints not found. Assuming old Fabric.",
+ "modloadingscreen.log.mod_loading_early": "[ModLoadingScreen] I just want to say... I'm loading *really* early.",
+ "modloadingscreen.log.dual_install_warn1": "[ModLoadingScreen] [WARN] Mod Loading Screen installed as both a mod and an agent.",
+ "modloadingscreen.log.dual_install_warn2": "[ModLoadingScreen] [WARN] Please avoid doing this. To avoid issues, the mod has disabled itself.",
+ "modloadingscreen.log.init_failed": "[ModLoadingScreen] Failed to initialize loading screen. Aborting!"
+}
From 3437560155c91bc798977177c985e254bfb85b77 Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 09:19:34 +0800
Subject: [PATCH 10/26] Delete
src/main/resources/assets/mod-loading-screen/en_us.json
---
.../assets/mod-loading-screen/en_us.json | 37 -------------------
1 file changed, 37 deletions(-)
delete mode 100644 src/main/resources/assets/mod-loading-screen/en_us.json
diff --git a/src/main/resources/assets/mod-loading-screen/en_us.json b/src/main/resources/assets/mod-loading-screen/en_us.json
deleted file mode 100644
index d8a1ce2..0000000
--- a/src/main/resources/assets/mod-loading-screen/en_us.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "modloadingscreen.feature.final_entrypoints": "Final Entrypoints",
- "modloadingscreen.feature.headless_check": "Headless Check",
- "modloadingscreen.feature.ipc_check": "IPC Check",
- "modloadingscreen.feature.get_progress": "Get Progress",
- "modloadingscreen.feature.open_check": "Open Check",
- "modloadingscreen.feature.custom_progress_bars": "Custom Progress Bars",
- "modloadingscreen.feature.unknown": "Unknown Feature",
-
- "modloadingscreen.title.loading_quilt": "Loading Quilt Loader",
- "modloadingscreen.title.loading_fabric": "Loading Fabric Loader",
- "modloadingscreen.title.loading_mod": "Loading %s %s",
-
- "modloadingscreen.memory.usage": "%d MB / %d MB",
-
- "modloadingscreen.entrypoint.status": "Loading '%s' (%s) \u2014 %d/%d",
- "modloadingscreen.entrypoint.status_mod": "Loading '%s' (%s) \u2014 %d/%d \u2014 %s",
-
- "modloadingscreen.error.ipc_client": "An error occurred in Mod Loading Screen's IPC client\n%s",
- "modloadingscreen.error.ipc_client_title": "Mod Loading Screen IPC Client",
- "modloadingscreen.error.fake_entrypoint_unsupported": "Fake entrypoint only supported on PreLaunchEntrypoint",
-
- "modloadingscreen.log.early_loading": "[ModLoadingScreen] I just want to say... I'm loading *really* **extremely** early.",
- "modloadingscreen.log.flatlaf_not_found": "[ModLoadingScreen] [ERROR] flatlaf.jar not found! Aborting.",
- "modloadingscreen.log.extracted_flatlaf": "[ModLoadingScreen] Extracted flatlaf.jar",
- "modloadingscreen.log.dump_active": "[ModLoadingScreen] Transformed class dumping is active",
- "modloadingscreen.log.dump_clear_failed": "[ModLoadingScreen] [ERROR] Failed to clear debug dump dir",
- "modloadingscreen.log.transforming": "[ModLoadingScreen] Transforming %s",
- "modloadingscreen.log.transformer_failed": "[ModLoadingScreen] [ERROR] Transformer %s for %s failed",
- "modloadingscreen.log.dump_failed": "[ModLoadingScreen] [ERROR] Failed to dump class %s",
- "modloadingscreen.log.transform_failed": "[ModLoadingScreen] [ERROR] Completely failed to transform %s",
- "modloadingscreen.log.old_fabric_fallback": "[ModLoadingScreen] New-style FabricLoaderImpl.invokeEntrypoints not found. Assuming old Fabric.",
- "modloadingscreen.log.mod_loading_early": "[ModLoadingScreen] I just want to say... I'm loading *really* early.",
- "modloadingscreen.log.dual_install_warn1": "[ModLoadingScreen] [WARN] Mod Loading Screen installed as both a mod and an agent.",
- "modloadingscreen.log.dual_install_warn2": "[ModLoadingScreen] [WARN] Please avoid doing this. To avoid issues, the mod has disabled itself.",
- "modloadingscreen.log.init_failed": "[ModLoadingScreen] Failed to initialize loading screen. Aborting!"
-}
From c2f511f66e0d2e32b6195d22303a9f58856ce503 Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 09:20:33 +0800
Subject: [PATCH 11/26] Add English localization for mod loading screen
---
.../assets/mod-loading-screen/lang/en_us.jspn | 37 +++++++++++++++++++
1 file changed, 37 insertions(+)
create mode 100644 src/main/resources/assets/mod-loading-screen/lang/en_us.jspn
diff --git a/src/main/resources/assets/mod-loading-screen/lang/en_us.jspn b/src/main/resources/assets/mod-loading-screen/lang/en_us.jspn
new file mode 100644
index 0000000..d8a1ce2
--- /dev/null
+++ b/src/main/resources/assets/mod-loading-screen/lang/en_us.jspn
@@ -0,0 +1,37 @@
+{
+ "modloadingscreen.feature.final_entrypoints": "Final Entrypoints",
+ "modloadingscreen.feature.headless_check": "Headless Check",
+ "modloadingscreen.feature.ipc_check": "IPC Check",
+ "modloadingscreen.feature.get_progress": "Get Progress",
+ "modloadingscreen.feature.open_check": "Open Check",
+ "modloadingscreen.feature.custom_progress_bars": "Custom Progress Bars",
+ "modloadingscreen.feature.unknown": "Unknown Feature",
+
+ "modloadingscreen.title.loading_quilt": "Loading Quilt Loader",
+ "modloadingscreen.title.loading_fabric": "Loading Fabric Loader",
+ "modloadingscreen.title.loading_mod": "Loading %s %s",
+
+ "modloadingscreen.memory.usage": "%d MB / %d MB",
+
+ "modloadingscreen.entrypoint.status": "Loading '%s' (%s) \u2014 %d/%d",
+ "modloadingscreen.entrypoint.status_mod": "Loading '%s' (%s) \u2014 %d/%d \u2014 %s",
+
+ "modloadingscreen.error.ipc_client": "An error occurred in Mod Loading Screen's IPC client\n%s",
+ "modloadingscreen.error.ipc_client_title": "Mod Loading Screen IPC Client",
+ "modloadingscreen.error.fake_entrypoint_unsupported": "Fake entrypoint only supported on PreLaunchEntrypoint",
+
+ "modloadingscreen.log.early_loading": "[ModLoadingScreen] I just want to say... I'm loading *really* **extremely** early.",
+ "modloadingscreen.log.flatlaf_not_found": "[ModLoadingScreen] [ERROR] flatlaf.jar not found! Aborting.",
+ "modloadingscreen.log.extracted_flatlaf": "[ModLoadingScreen] Extracted flatlaf.jar",
+ "modloadingscreen.log.dump_active": "[ModLoadingScreen] Transformed class dumping is active",
+ "modloadingscreen.log.dump_clear_failed": "[ModLoadingScreen] [ERROR] Failed to clear debug dump dir",
+ "modloadingscreen.log.transforming": "[ModLoadingScreen] Transforming %s",
+ "modloadingscreen.log.transformer_failed": "[ModLoadingScreen] [ERROR] Transformer %s for %s failed",
+ "modloadingscreen.log.dump_failed": "[ModLoadingScreen] [ERROR] Failed to dump class %s",
+ "modloadingscreen.log.transform_failed": "[ModLoadingScreen] [ERROR] Completely failed to transform %s",
+ "modloadingscreen.log.old_fabric_fallback": "[ModLoadingScreen] New-style FabricLoaderImpl.invokeEntrypoints not found. Assuming old Fabric.",
+ "modloadingscreen.log.mod_loading_early": "[ModLoadingScreen] I just want to say... I'm loading *really* early.",
+ "modloadingscreen.log.dual_install_warn1": "[ModLoadingScreen] [WARN] Mod Loading Screen installed as both a mod and an agent.",
+ "modloadingscreen.log.dual_install_warn2": "[ModLoadingScreen] [WARN] Please avoid doing this. To avoid issues, the mod has disabled itself.",
+ "modloadingscreen.log.init_failed": "[ModLoadingScreen] Failed to initialize loading screen. Aborting!"
+}
From c47b07e0813e5793eada790806f12077886b68a6 Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 09:27:04 +0800
Subject: [PATCH 12/26] Create zh_tw.json for mod loading screen localization
Add Traditional Chinese translations for mod loading screen.
---
.../assets/mod-loading-screen/lang/zh_tw.json | 39 +++++++++++++++++++
1 file changed, 39 insertions(+)
create mode 100644 src/main/resources/assets/mod-loading-screen/lang/zh_tw.json
diff --git a/src/main/resources/assets/mod-loading-screen/lang/zh_tw.json b/src/main/resources/assets/mod-loading-screen/lang/zh_tw.json
new file mode 100644
index 0000000..5c695cf
--- /dev/null
+++ b/src/main/resources/assets/mod-loading-screen/lang/zh_tw.json
@@ -0,0 +1,39 @@
+{
+ "modmenu.nameTranslation.mod-loading-screen": "模組載入畫面",
+ "modmenu.descriptionTranslation.mod-loading-screen": "帶有模組載入進度的高級載入畫面",
+ "modloadingscreen.feature.final_entrypoints": "最終進入點",
+ "modloadingscreen.feature.headless_check": "無介面模式檢查",
+ "modloadingscreen.feature.ipc_check": "IPC 檢查",
+ "modloadingscreen.feature.get_progress": "讀取進度",
+ "modloadingscreen.feature.open_check": "開啟狀態檢查",
+ "modloadingscreen.feature.custom_progress_bars": "自訂進度條",
+ "modloadingscreen.feature.unknown": "未知特性",
+
+ "modloadingscreen.title.loading_quilt": "正在載入 Quilt Loader",
+ "modloadingscreen.title.loading_fabric": "正在載入 Fabric Loader",
+ "modloadingscreen.title.loading_mod": "正在載入 %s %s",
+
+ "modloadingscreen.memory.usage": "%d MB / %d MB",
+
+ "modloadingscreen.entrypoint.status": "正在載入 '%s' (%s) \u2014 %d/%d",
+ "modloadingscreen.entrypoint.status_mod": "正在載入 '%s' (%s) \u2014 %d/%d \u2014 %s",
+
+ "modloadingscreen.error.ipc_client": "模組載入畫面 的 IPC 客戶端發生錯誤\n%s",
+ "modloadingscreen.error.ipc_client_title": "模組載入畫面 IPC 客戶端",
+ "modloadingscreen.error.fake_entrypoint_unsupported": "偽進入點僅支援 PreLaunchEntrypoint",
+
+ "modloadingscreen.log.early_loading": "[ModLoadingScreen] 我只想說... 我的載入時機真的 *非常* **極度** 早期。",
+ "modloadingscreen.log.flatlaf_not_found": "[模組載入畫面] [錯誤] 找不到 flatlaf.jar!正在中止。",
+ "modloadingscreen.log.extracted_flatlaf": "[模組載入畫面] 已解壓縮 flatlaf.jar",
+ "modloadingscreen.log.dump_active": "[模組載入畫面] 已啟用轉換類別轉儲功能",
+ "modloadingscreen.log.dump_clear_failed": "[模組載入畫面] [錯誤] 清空除錯轉儲目錄失敗",
+ "modloadingscreen.log.transforming": "[模組載入畫面] 正在轉換 %s",
+ "modloadingscreen.log.transformer_failed": "[模組載入畫面] [錯誤] %2$s 的轉換器 %1$s 執行失敗",
+ "modloadingscreen.log.dump_failed": "[模組載入畫面] [錯誤] 轉儲類別 %s 失敗",
+ "modloadingscreen.log.transform_failed": "[模組載入畫面] [錯誤] 完全無法轉換 %s",
+ "modloadingscreen.log.old_fabric_fallback": "[模組載入畫面] 未找到新版 FabricLoaderImpl.invokeEntrypoints,將視為舊版 Fabric。",
+ "modloadingscreen.log.mod_loading_early": "[模組載入畫面] 我只想說... 我的載入時機真的 *非常* 早期。",
+ "modloadingscreen.log.dual_install_warn1": "[模組載入畫面] [警告] Mod Loading Screen 同時以模組和 Agent 方式安裝。",
+ "modloadingscreen.log.dual_install_warn2": "[模組載入畫面] [警告] 請避免這樣做。為避免問題,模組已自動停用。",
+ "modloadingscreen.log.init_failed": "[模組載入畫面] 初始化載入畫面失敗。正在中止!"
+}
From 1245523f15c60fed2b350a5161f99dfd255e3d5c Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 09:28:45 +0800
Subject: [PATCH 13/26] Repair file extensions
---
.../assets/mod-loading-screen/lang/{en_us.jspn => en_us.json} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename src/main/resources/assets/mod-loading-screen/lang/{en_us.jspn => en_us.json} (100%)
diff --git a/src/main/resources/assets/mod-loading-screen/lang/en_us.jspn b/src/main/resources/assets/mod-loading-screen/lang/en_us.json
similarity index 100%
rename from src/main/resources/assets/mod-loading-screen/lang/en_us.jspn
rename to src/main/resources/assets/mod-loading-screen/lang/en_us.json
From 53f32694ced3d92938c5a8b24818a4605c06614d Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 09:31:06 +0800
Subject: [PATCH 14/26] Update GitHub Actions to use latest action versions
---
.github/workflows/gradle.yml | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
index f16f0cb..036a7c8 100644
--- a/.github/workflows/gradle.yml
+++ b/.github/workflows/gradle.yml
@@ -1,20 +1,23 @@
name: gradle
-on: [push, pull_request, workflow_dispatch]
+on:
+ workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
- name: Set up JDK 17
- uses: actions/setup-java@v2.1.0
+ uses: actions/setup-java@v4
with:
java-version: 17
distribution: zulu
+ - name: Grant execute permission for gradlew
+ run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew build
- name: Upload build JARs
- uses: actions/upload-artifact@v2.3.1
+ uses: actions/upload-artifact@v4
with:
name: build-jars
path: build/libs/*
From 91f1411b4a77e1b950c41479a958bb0286447695 Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 09:34:13 +0800
Subject: [PATCH 15/26] Refactor CustomProgressBar title argument handling
---
.../modloadingscreen/api/CustomProgressBar.java | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/src/api/java/io/github/gaming32/modloadingscreen/api/CustomProgressBar.java b/src/api/java/io/github/gaming32/modloadingscreen/api/CustomProgressBar.java
index 388eccb..60fad5c 100644
--- a/src/api/java/io/github/gaming32/modloadingscreen/api/CustomProgressBar.java
+++ b/src/api/java/io/github/gaming32/modloadingscreen/api/CustomProgressBar.java
@@ -98,15 +98,12 @@ public void setTitle(String titleKey, String... titleArgs) {
checkClosed();
this.titleKey = titleKey;
this.titleArgs = titleArgs != null ? titleArgs : new String[0];
- if (this.titleArgs.length > 0) {
- String[] opArgs = new String[this.titleArgs.length + 2];
- opArgs[0] = "title";
- opArgs[1] = titleKey;
- System.arraycopy(this.titleArgs, 0, opArgs, 2, this.titleArgs.length);
- LoadingScreenApi.customProgressBarOp(id, opArgs);
- } else {
- LoadingScreenApi.customProgressBarOp(id, "title", titleKey);
- }
+ String[] opArgs = new String[this.titleArgs.length + 3];
+ opArgs[0] = id;
+ opArgs[1] = "title";
+ opArgs[2] = titleKey;
+ System.arraycopy(this.titleArgs, 0, opArgs, 3, this.titleArgs.length);
+ LoadingScreenApi.customProgressBarOp(opArgs);
}
public String getTitleKey() {
From 750b1ff336e37f16cc98a9589772fcfb54690257 Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 09:46:32 +0800
Subject: [PATCH 16/26] Implement game version management in loading screen
Added game version handling and updated loading screen title logic.
---
.../modloadingscreen/ActualLoadingScreen.java | 61 ++++++++++++++++---
1 file changed, 53 insertions(+), 8 deletions(-)
diff --git a/src/main/java/io/github/gaming32/modloadingscreen/ActualLoadingScreen.java b/src/main/java/io/github/gaming32/modloadingscreen/ActualLoadingScreen.java
index 51c489c..01e1882 100644
--- a/src/main/java/io/github/gaming32/modloadingscreen/ActualLoadingScreen.java
+++ b/src/main/java/io/github/gaming32/modloadingscreen/ActualLoadingScreen.java
@@ -67,6 +67,7 @@ public class ActualLoadingScreen {
private static boolean titleSet;
static boolean runningOnQuilt;
+ private static String gameVersion;
private static Path configDir;
private static boolean enableMemoryDisplay = true;
@@ -115,6 +116,14 @@ public static String translate(String key, Object... args) {
}
}
+ public static String getLoaderName() {
+ return runningOnQuilt ? translate("modloadingscreen.loader.quilt") : translate("modloadingscreen.loader.fabric");
+ }
+
+ private static String getLoaderIconName() {
+ return runningOnQuilt ? "icon-quilt.png" : "icon-fabric.png";
+ }
+
public static void startLoadingScreen(boolean fabricReady) {
loadTranslations();
@@ -142,13 +151,18 @@ public static void startLoadingScreen(boolean fabricReady) {
if (IS_IPC_CLIENT) {
runningOnQuilt = Boolean.getBoolean("mlsipc.quilt");
+ gameVersion = System.getProperty("mlsipc.gameVersion");
configDir = Paths.get(System.getProperty("mlsipc.config"));
} else {
if (fabricReady) {
runningOnQuilt = FabricLoader.getInstance().isModLoaded("quilt_loader");
+ gameVersion = FabricLoader.getInstance().getModContainer("minecraft")
+ .map(c -> c.getMetadata().getVersion().getFriendlyString())
+ .orElse(null);
configDir = FabricLoader.getInstance().getConfigDir().resolve("mod-loading-screen");
} else {
- runningOnQuilt = System.getProperty("java.class.path").contains("quilt-loader");
+ final String classpath = System.getProperty("java.class.path");
+ runningOnQuilt = classpath.contains("quilt-loader");
configDir = Paths.get("config/mod-loading-screen").toAbsolutePath();
}
}
@@ -197,6 +211,7 @@ public static void startLoadingScreen(boolean fabricReady) {
System.getProperty("java.home") + "/bin/java",
"-Dmlsipc.present=true",
"-Dmlsipc.quilt=" + runningOnQuilt,
+ "-Dmlsipc.gameVersion=" + (gameVersion != null ? gameVersion : ""),
"-Dmlsipc.config=" + configDir,
"-cp", mlsJarPath + File.pathSeparator + flatlafDestPath,
ACTUAL_LOADING_SCREEN.replace('/', '.')
@@ -228,21 +243,24 @@ public static void startLoadingScreen(boolean fabricReady) {
if (fabricReady) {
setFabricTitle();
} else {
- dialog.setTitle(translate(runningOnQuilt ? "modloadingscreen.title.loading_quilt" : "modloadingscreen.title.loading_fabric"));
+ updateTitleWithGameVersion();
}
dialog.setResizable(false);
try {
- dialog.setIconImage(ImageIO.read(findImageUrl("icon", "icon.png", ImageIO.getReaderFileSuffixes())));
+ dialog.setIconImage(ImageIO.read(findImageUrl("icon", getLoaderIconName(), ImageIO.getReaderFileSuffixes())));
} catch (Exception e) {
- println("Failed to load icon.png", e);
+ try {
+ dialog.setIconImage(ImageIO.read(findImageUrl("icon", "icon.png", ImageIO.getReaderFileSuffixes())));
+ } catch (Exception ex) {
+ println("Failed to load icon", ex);
+ }
}
ImageIcon background;
try {
- background = new ImageIcon(findImageUrl(
- "background", runningOnQuilt ? "quilt-banner.png" : "aof4.png", SUPPORTED_BACKGROUND_FORMATS
- ));
+ String defaultBanner = runningOnQuilt ? "quilt-banner.png" : "aof4.png";
+ background = new ImageIcon(findImageUrl("background", defaultBanner, SUPPORTED_BACKGROUND_FORMATS));
} catch (Exception e) {
println("Failed to load background.png", e);
background = null;
@@ -307,7 +325,9 @@ private static URL findImageUrl(
return path.toUri().toURL();
}
}
- return ClassLoader.getSystemResource("assets/mod-loading-screen/" + defaultFilename);
+ URL res = ClassLoader.getSystemResource("assets/mod-loading-screen/" + defaultFilename);
+ if (res != null) return res;
+ return ClassLoader.getSystemResource("assets/mod-loading-screen/icon.png");
}
private static void startMemoryThread() {
@@ -328,7 +348,26 @@ private static void startMemoryThread() {
memoryThread.start();
}
+ public static void setGameVersion(String version) {
+ if (version == null || version.isEmpty()) return;
+ gameVersion = version;
+ sendIpc(7, version);
+ updateTitleWithGameVersion();
+ }
+
+ private static void updateTitleWithGameVersion() {
+ if (titleSet) return;
+ if (gameVersion != null && !gameVersion.isEmpty()) {
+ setTitle(translate("modloadingscreen.title.loading_loader_game", getLoaderName(), gameVersion));
+ } else {
+ setTitle(translate("modloadingscreen.title.loading_loader", getLoaderName()));
+ }
+ }
+
public static void setTitleFromMetadata(String id, String name, String version) {
+ if (id != null && (id.equals("minecraft") || id.equalsIgnoreCase("game"))) {
+ setGameVersion(version);
+ }
if (titleSet || IGNORED_BUILTIN.contains(id)) return;
titleSet = true;
setTitle(translate("modloadingscreen.title.loading_mod", name, version));
@@ -337,6 +376,9 @@ public static void setTitleFromMetadata(String id, String name, String version)
private static void setFabricTitle() {
for (final ModContainer container : FabricLoader.getInstance().getAllMods()) {
final ModMetadata m = container.getMetadata();
+ if (m.getId().equals("minecraft")) {
+ setGameVersion(m.getVersion().getFriendlyString());
+ }
if (!m.getType().equals("builtin")) continue;
setTitleFromMetadata(m.getId(), m.getName(), m.getVersion().getFriendlyString());
if (titleSet) break;
@@ -644,6 +686,9 @@ public static void main(String[] args) {
case 6:
setTitle(packetArgs[0]);
break;
+ case 7:
+ setGameVersion(packetArgs[0]);
+ break;
case 255:
break mainLoop;
}
From 045a677eb1639a91d3ba3693e6309312c67cf9fc Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 09:49:53 +0800
Subject: [PATCH 17/26] Refactor loading screen title update logic
---
.../modloadingscreen/ActualLoadingScreen.java | 43 +++++++++----------
1 file changed, 20 insertions(+), 23 deletions(-)
diff --git a/src/main/java/io/github/gaming32/modloadingscreen/ActualLoadingScreen.java b/src/main/java/io/github/gaming32/modloadingscreen/ActualLoadingScreen.java
index 01e1882..e85ce60 100644
--- a/src/main/java/io/github/gaming32/modloadingscreen/ActualLoadingScreen.java
+++ b/src/main/java/io/github/gaming32/modloadingscreen/ActualLoadingScreen.java
@@ -240,21 +240,13 @@ public static void startLoadingScreen(boolean fabricReady) {
UIManager.getDefaults().put("ProgressBar.selectionForeground", new Color(255, 255, 255));
dialog = new JFrame();
- if (fabricReady) {
- setFabricTitle();
- } else {
- updateTitleWithGameVersion();
- }
+ updateTitleWithGameVersion();
dialog.setResizable(false);
try {
dialog.setIconImage(ImageIO.read(findImageUrl("icon", getLoaderIconName(), ImageIO.getReaderFileSuffixes())));
} catch (Exception e) {
- try {
- dialog.setIconImage(ImageIO.read(findImageUrl("icon", "icon.png", ImageIO.getReaderFileSuffixes())));
- } catch (Exception ex) {
- println("Failed to load icon", ex);
- }
+ println("Failed to load icon", e);
}
ImageIcon background;
@@ -319,15 +311,25 @@ private static void loadConfig() {
private static URL findImageUrl(
String prefix, String defaultFilename, String[] formats
) throws MalformedURLException {
+ URL res = ClassLoader.getSystemResource("assets/mod-loading-screen/" + defaultFilename);
+ if (res != null) return res;
+
+ res = ClassLoader.getSystemResource("assets/mod-loading-screen/icon.png");
+ if (res != null) return res;
+
+ final Path specificConfigPath = configDir.resolve(defaultFilename);
+ if (Files.isRegularFile(specificConfigPath)) {
+ return specificConfigPath.toUri().toURL();
+ }
+
for (final String format : formats) {
final Path path = configDir.resolve(prefix + '.' + format);
if (Files.isRegularFile(path)) {
return path.toUri().toURL();
}
}
- URL res = ClassLoader.getSystemResource("assets/mod-loading-screen/" + defaultFilename);
- if (res != null) return res;
- return ClassLoader.getSystemResource("assets/mod-loading-screen/icon.png");
+
+ return null;
}
private static void startMemoryThread() {
@@ -356,7 +358,6 @@ public static void setGameVersion(String version) {
}
private static void updateTitleWithGameVersion() {
- if (titleSet) return;
if (gameVersion != null && !gameVersion.isEmpty()) {
setTitle(translate("modloadingscreen.title.loading_loader_game", getLoaderName(), gameVersion));
} else {
@@ -367,6 +368,7 @@ private static void updateTitleWithGameVersion() {
public static void setTitleFromMetadata(String id, String name, String version) {
if (id != null && (id.equals("minecraft") || id.equalsIgnoreCase("game"))) {
setGameVersion(version);
+ return;
}
if (titleSet || IGNORED_BUILTIN.contains(id)) return;
titleSet = true;
@@ -374,15 +376,10 @@ public static void setTitleFromMetadata(String id, String name, String version)
}
private static void setFabricTitle() {
- for (final ModContainer container : FabricLoader.getInstance().getAllMods()) {
- final ModMetadata m = container.getMetadata();
- if (m.getId().equals("minecraft")) {
- setGameVersion(m.getVersion().getFriendlyString());
- }
- if (!m.getType().equals("builtin")) continue;
- setTitleFromMetadata(m.getId(), m.getName(), m.getVersion().getFriendlyString());
- if (titleSet) break;
- }
+ FabricLoader.getInstance().getModContainer("minecraft").ifPresent(container -> {
+ setGameVersion(container.getMetadata().getVersion().getFriendlyString());
+ });
+ updateTitleWithGameVersion();
}
private static void setTitle(String title) {
From f63015f2ab7e9bdd102f8b647f858501fd5574e0 Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 09:51:24 +0800
Subject: [PATCH 18/26] Add files via upload
---
.../assets/mod-loading-screen/Fabric.png | Bin 0 -> 1386 bytes
.../assets/mod-loading-screen/Quilt.png | Bin 0 -> 4215 bytes
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 src/main/resources/assets/mod-loading-screen/Fabric.png
create mode 100644 src/main/resources/assets/mod-loading-screen/Quilt.png
diff --git a/src/main/resources/assets/mod-loading-screen/Fabric.png b/src/main/resources/assets/mod-loading-screen/Fabric.png
new file mode 100644
index 0000000000000000000000000000000000000000..bb3f0a4c290ee4a43f699c2e936e6f1467a32aca
GIT binary patch
literal 1386
zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST~P>fz{B{#WAE}&YQdEv!~vaJ^nHI
zqx;T(F%nxd%}l#|qd2E+32mv;ocfMs_xpAAj^eRXv%JG&zv#bM_gm}^S5SBq#}uU<
z8nIp>6NhmiosnWI`WX3yOj7FnN{x$ytqrLFJyu0%y!6mQ!4XwK^B?eC{ttN(rG
zg`dhXoiy_ptw*WNBaHCy|o^%OV~xA3Zea6KtDZx(@7*gb$lGf95$``&s(!kBu`g&5Qs4u7By*!xnyL=j*(c
zbXSPmh&ydGCMdm6l6>{;TU&koSL18{KJVE4x#!iv!&g7uUA0^LyS04H3%njl-q{^0
z`|8`=*2{n2>&<)j&Ov$Bk%f8H-`?a^e=qr+98>${{4z@T5e8iOrAMn%{2Q`gQ-MdDY*u=NINY
z^RTunUb1avhK%!Fwr2j@VIO0z>feaDe`AlGZu#m}Hh3~dV}efk##PQos`k47y%x29
z)AL8If0r8D)<*rmd*SQdwShg!D{g=OpZ|Yt)w)c>bq=S*ffhJwPAK;7zS^H5zxUUY
zEpxRp%|9apYl1cDDbmXV)fQl2bcv!fI4__~pN^5AMH}|F2W`S5NpTUN`uheXyf&
z1>bV%qj#tNu2T~}f;UGkOVhh%5z>B{(Z>{Te0<0R7MuV7Gg~Y9n*4b^9mrwuboFyt
I=akR{03>2cGynhq
literal 0
HcmV?d00001
diff --git a/src/main/resources/assets/mod-loading-screen/Quilt.png b/src/main/resources/assets/mod-loading-screen/Quilt.png
new file mode 100644
index 0000000000000000000000000000000000000000..9206ed678ea828bbcab0c6e05390ea608332e041
GIT binary patch
literal 4215
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
literal 0
HcmV?d00001
From 537e736a49c1566cc10e70e31be29263fef50b06 Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 09:53:32 +0800
Subject: [PATCH 19/26] Rename the icon
---
.../{Fabric.png => icon-fabric.png} | Bin
.../{Quilt.png => icon-quilt.png} | Bin
2 files changed, 0 insertions(+), 0 deletions(-)
rename src/main/resources/assets/mod-loading-screen/{Fabric.png => icon-fabric.png} (100%)
rename src/main/resources/assets/mod-loading-screen/{Quilt.png => icon-quilt.png} (100%)
diff --git a/src/main/resources/assets/mod-loading-screen/Fabric.png b/src/main/resources/assets/mod-loading-screen/icon-fabric.png
similarity index 100%
rename from src/main/resources/assets/mod-loading-screen/Fabric.png
rename to src/main/resources/assets/mod-loading-screen/icon-fabric.png
diff --git a/src/main/resources/assets/mod-loading-screen/Quilt.png b/src/main/resources/assets/mod-loading-screen/icon-quilt.png
similarity index 100%
rename from src/main/resources/assets/mod-loading-screen/Quilt.png
rename to src/main/resources/assets/mod-loading-screen/icon-quilt.png
From 5fdbe67ec9dfb3d53456d4b7d4eeaf8b2cd2cb8c Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 09:58:28 +0800
Subject: [PATCH 20/26] Update Chinese translations in zh_tw.json
---
.../assets/mod-loading-screen/lang/zh_tw.json | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/main/resources/assets/mod-loading-screen/lang/zh_tw.json b/src/main/resources/assets/mod-loading-screen/lang/zh_tw.json
index 5c695cf..392ed01 100644
--- a/src/main/resources/assets/mod-loading-screen/lang/zh_tw.json
+++ b/src/main/resources/assets/mod-loading-screen/lang/zh_tw.json
@@ -1,6 +1,12 @@
{
"modmenu.nameTranslation.mod-loading-screen": "模組載入畫面",
"modmenu.descriptionTranslation.mod-loading-screen": "帶有模組載入進度的高級載入畫面",
+
+ "modloadingscreen.loader.fabric": "Fabric",
+ "modloadingscreen.loader.quilt": "Quilt",
+ "modloadingscreen.title.loading_loader": "正在載入%s",
+ "modloadingscreen.title.loading_loader_game": "正在載入%s[%s]",
+
"modloadingscreen.feature.final_entrypoints": "最終進入點",
"modloadingscreen.feature.headless_check": "無介面模式檢查",
"modloadingscreen.feature.ipc_check": "IPC 檢查",
@@ -22,7 +28,7 @@
"modloadingscreen.error.ipc_client_title": "模組載入畫面 IPC 客戶端",
"modloadingscreen.error.fake_entrypoint_unsupported": "偽進入點僅支援 PreLaunchEntrypoint",
- "modloadingscreen.log.early_loading": "[ModLoadingScreen] 我只想說... 我的載入時機真的 *非常* **極度** 早期。",
+ "modloadingscreen.log.early_loading": "[模組載入畫面] 我只想說... 我的載入時機真的 *非常* **極度** 早期。",
"modloadingscreen.log.flatlaf_not_found": "[模組載入畫面] [錯誤] 找不到 flatlaf.jar!正在中止。",
"modloadingscreen.log.extracted_flatlaf": "[模組載入畫面] 已解壓縮 flatlaf.jar",
"modloadingscreen.log.dump_active": "[模組載入畫面] 已啟用轉換類別轉儲功能",
@@ -33,7 +39,7 @@
"modloadingscreen.log.transform_failed": "[模組載入畫面] [錯誤] 完全無法轉換 %s",
"modloadingscreen.log.old_fabric_fallback": "[模組載入畫面] 未找到新版 FabricLoaderImpl.invokeEntrypoints,將視為舊版 Fabric。",
"modloadingscreen.log.mod_loading_early": "[模組載入畫面] 我只想說... 我的載入時機真的 *非常* 早期。",
- "modloadingscreen.log.dual_install_warn1": "[模組載入畫面] [警告] Mod Loading Screen 同時以模組和 Agent 方式安裝。",
+ "modloadingscreen.log.dual_install_warn1": "[模組載入畫面] [警告] 模組載入畫面 同時以模組和 Agent 方式安裝。",
"modloadingscreen.log.dual_install_warn2": "[模組載入畫面] [警告] 請避免這樣做。為避免問題,模組已自動停用。",
"modloadingscreen.log.init_failed": "[模組載入畫面] 初始化載入畫面失敗。正在中止!"
}
From 1e006f55ba5d8284932261af3987e08dca666d13 Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 09:58:41 +0800
Subject: [PATCH 21/26] Add translations for mod loading screen
---
.../resources/assets/mod-loading-screen/lang/en_us.json | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/main/resources/assets/mod-loading-screen/lang/en_us.json b/src/main/resources/assets/mod-loading-screen/lang/en_us.json
index d8a1ce2..8494f8f 100644
--- a/src/main/resources/assets/mod-loading-screen/lang/en_us.json
+++ b/src/main/resources/assets/mod-loading-screen/lang/en_us.json
@@ -1,4 +1,12 @@
{
+ "modmenu.nameTranslation.mod-loading-screen": "Mod Loading Screen",
+ "modmenu.descriptionTranslation.mod-loading-screen": "A fancy loading screen that shows the progress of loading mods",
+
+ "modloadingscreen.loader.fabric": "Fabric",
+ "modloadingscreen.loader.quilt": "Quilt",
+ "modloadingscreen.title.loading_loader": "Loading %s",
+ "modloadingscreen.title.loading_loader_game": "Loading %s [%s]",
+
"modloadingscreen.feature.final_entrypoints": "Final Entrypoints",
"modloadingscreen.feature.headless_check": "Headless Check",
"modloadingscreen.feature.ipc_check": "IPC Check",
From 54dbdfeacbb6f324dc497c7bc5e3c6a9cf42bb36 Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 10:04:53 +0800
Subject: [PATCH 22/26] Fix loading message format in en_us.json
---
src/main/resources/assets/mod-loading-screen/lang/en_us.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/resources/assets/mod-loading-screen/lang/en_us.json b/src/main/resources/assets/mod-loading-screen/lang/en_us.json
index 8494f8f..2f68c26 100644
--- a/src/main/resources/assets/mod-loading-screen/lang/en_us.json
+++ b/src/main/resources/assets/mod-loading-screen/lang/en_us.json
@@ -5,7 +5,7 @@
"modloadingscreen.loader.fabric": "Fabric",
"modloadingscreen.loader.quilt": "Quilt",
"modloadingscreen.title.loading_loader": "Loading %s",
- "modloadingscreen.title.loading_loader_game": "Loading %s [%s]",
+ "modloadingscreen.title.loading_loader_game": "Loading %s %s",
"modloadingscreen.feature.final_entrypoints": "Final Entrypoints",
"modloadingscreen.feature.headless_check": "Headless Check",
From 910a8c4b7eed374641c4a40a597fce543b257c33 Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 10:05:25 +0800
Subject: [PATCH 23/26] Fix loading message format in zh_tw.json
---
src/main/resources/assets/mod-loading-screen/lang/zh_tw.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/resources/assets/mod-loading-screen/lang/zh_tw.json b/src/main/resources/assets/mod-loading-screen/lang/zh_tw.json
index 392ed01..837055f 100644
--- a/src/main/resources/assets/mod-loading-screen/lang/zh_tw.json
+++ b/src/main/resources/assets/mod-loading-screen/lang/zh_tw.json
@@ -5,7 +5,7 @@
"modloadingscreen.loader.fabric": "Fabric",
"modloadingscreen.loader.quilt": "Quilt",
"modloadingscreen.title.loading_loader": "正在載入%s",
- "modloadingscreen.title.loading_loader_game": "正在載入%s[%s]",
+ "modloadingscreen.title.loading_loader_game": "正在載入%s %s",
"modloadingscreen.feature.final_entrypoints": "最終進入點",
"modloadingscreen.feature.headless_check": "無介面模式檢查",
From 28322c11c657edf6dd290fac23979d6113f71fab Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 10:42:54 +0800
Subject: [PATCH 24/26] Update Gradle workflow to use specific action versions
---
.github/workflows/gradle.yml | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
index 036a7c8..f16f0cb 100644
--- a/.github/workflows/gradle.yml
+++ b/.github/workflows/gradle.yml
@@ -1,23 +1,20 @@
name: gradle
-on:
- workflow_dispatch:
+on: [push, pull_request, workflow_dispatch]
jobs:
build:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v2
- name: Set up JDK 17
- uses: actions/setup-java@v4
+ uses: actions/setup-java@v2.1.0
with:
java-version: 17
distribution: zulu
- - name: Grant execute permission for gradlew
- run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew build
- name: Upload build JARs
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v2.3.1
with:
name: build-jars
path: build/libs/*
From 95fee91e91fe1ba8165fe8312f5c0a73ca10ac20 Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 10:48:28 +0800
Subject: [PATCH 25/26] Update fabric.mod.json with contributors and contact
Added contributors and contact information to the mod JSON file.
---
src/main/resources/fabric.mod.json | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json
index c706e95..fc501a6 100644
--- a/src/main/resources/fabric.mod.json
+++ b/src/main/resources/fabric.mod.json
@@ -7,10 +7,24 @@
"authors": [
"Gaming32"
],
- "contact": {},
+ "contributors": [
+ "StarsShine11904"
+ ],
+ "contact": {
+ "homepage": "https://modrinth.com/mod/mod-loading-screen",
+ "sources": "https://github.com/Gaming32/mod-loading-screen",
+ "issues": "https://github.com/Gaming32/mod-loading-screen/issues"
+ },
"license": "MIT",
"icon": "assets/mod-loading-screen/icon.png",
- "environment": "*",
+ "environment": "client",
+ "custom": {
+ "modmenu": {
+ "badges": [
+ "client"
+ ]
+ }
+ },
"depends": {
"fabricloader": ">=0.12.0"
},
From b579c6c197304d0b957bd04b797b2eb1f51a90c5 Mon Sep 17 00:00:00 2001
From: StarsShine11904 <89504980+StarsShine11904@users.noreply.github.com>
Date: Mon, 7 Sep 2026 10:51:12 +0800
Subject: [PATCH 26/26] Upgrade GitHub Actions to latest versions
---
.github/workflows/gradle.yml | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
index f16f0cb..9b42691 100644
--- a/.github/workflows/gradle.yml
+++ b/.github/workflows/gradle.yml
@@ -5,16 +5,18 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
- name: Set up JDK 17
- uses: actions/setup-java@v2.1.0
+ uses: actions/setup-java@v4
with:
java-version: 17
distribution: zulu
+ - name: Grant execute permission for gradlew
+ run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew build
- name: Upload build JARs
- uses: actions/upload-artifact@v2.3.1
+ uses: actions/upload-artifact@v4
with:
name: build-jars
path: build/libs/*