diff --git a/src/main/java/com/falsepattern/lib/internal/Share.java b/src/main/java/com/falsepattern/lib/internal/Share.java
index 3cd24db..35a6657 100644
--- a/src/main/java/com/falsepattern/lib/internal/Share.java
+++ b/src/main/java/com/falsepattern/lib/internal/Share.java
@@ -22,6 +22,7 @@
package com.falsepattern.lib.internal;
+import com.falsepattern.lib.internal.asm.PreShare;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.val;
@@ -32,16 +33,7 @@ import java.io.IOException;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class Share {
- public static final boolean DEV_ENV;
-
- static {
- try {
- val bs = Launch.classLoader.getClassBytes("net.minecraft.world.World");
- DEV_ENV = bs != null;
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
+ public static final boolean DEV_ENV = PreShare.devEnv();
public static boolean EARLY_INIT_DONE = false;
}
diff --git a/src/main/java/com/falsepattern/lib/internal/asm/CoreLoadingPlugin.java b/src/main/java/com/falsepattern/lib/internal/asm/CoreLoadingPlugin.java
index 187f705..cd7f230 100644
--- a/src/main/java/com/falsepattern/lib/internal/asm/CoreLoadingPlugin.java
+++ b/src/main/java/com/falsepattern/lib/internal/asm/CoreLoadingPlugin.java
@@ -56,6 +56,7 @@ public class CoreLoadingPlugin implements IFMLLoadingPlugin {
private static boolean obfuscated;
static {
+ PreShare.initDevState(Launch.classLoader.findResource("net/minecraft/world/World.class") != null);
LetsEncryptHelper.replaceSSLContext();
FPLog.LOG.info("Removing skill issues...");
try {
@@ -67,7 +68,7 @@ public class CoreLoadingPlugin implements IFMLLoadingPlugin {
//Scan for dependencies now
FPLog.LOG.info("Scanning for deps...");
long start = System.nanoTime();
- DependencyLoaderImpl.executeDependencyLoading(true);
+ DependencyLoaderImpl.executeDependencyLoading();
long end = System.nanoTime();
FPLog.LOG.info("Scanned in " + (end - start) / 1000000 + "ms");
//Initializing the rest
diff --git a/src/main/java/com/falsepattern/lib/internal/asm/PreShare.java b/src/main/java/com/falsepattern/lib/internal/asm/PreShare.java
new file mode 100644
index 0000000..d9c40dc
--- /dev/null
+++ b/src/main/java/com/falsepattern/lib/internal/asm/PreShare.java
@@ -0,0 +1,41 @@
+/*
+ * This file is part of FalsePatternLib.
+ *
+ * Copyright (C) 2022-2025 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * FalsePatternLib is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * FalsePatternLib is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FalsePatternLib. If not, see .
+ */
+
+package com.falsepattern.lib.internal.asm;
+
+import lombok.Getter;
+
+public class PreShare {
+ private static volatile boolean devEnv = false;
+ private static volatile boolean inited = false;
+ public static synchronized void initDevState(boolean state) {
+ if (inited) {
+ return;
+ }
+ inited = true;
+ devEnv = state;
+ }
+
+ public static synchronized boolean devEnv() {
+ return devEnv;
+ }
+}
diff --git a/src/main/java/com/falsepattern/lib/internal/asm/RFBLoadingPlugin.java b/src/main/java/com/falsepattern/lib/internal/asm/RFBLoadingPlugin.java
index fe9db96..493a640 100644
--- a/src/main/java/com/falsepattern/lib/internal/asm/RFBLoadingPlugin.java
+++ b/src/main/java/com/falsepattern/lib/internal/asm/RFBLoadingPlugin.java
@@ -25,12 +25,31 @@ package com.falsepattern.lib.internal.asm;
import com.falsepattern.lib.internal.core.LowLevelCallMultiplexer;
import com.falsepattern.lib.internal.impl.dependencies.DependencyLoaderImpl;
import com.falsepattern.lib.internal.impl.dependencies.LetsEncryptHelper;
+import com.gtnewhorizons.retrofuturabootstrap.RfbApiImpl;
import com.gtnewhorizons.retrofuturabootstrap.api.RfbPlugin;
+import lombok.val;
+
+import java.net.URLClassLoader;
public class RFBLoadingPlugin implements RfbPlugin {
static {
+ val loader = RfbApiImpl.INSTANCE.launchClassLoader();
+ try {
+ val exc = loader.getClass()
+ .getDeclaredMethod("addClassLoaderExclusion", String.class);
+ exc.invoke(loader, "com.falsepattern.lib.dependencies.");
+ exc.invoke(loader, "com.falsepattern.lib.internal.impl.dependencies.");
+ exc.invoke(loader, "com.falsepattern.lib.internal.Internet");
+ exc.invoke(loader, "com.falsepattern.lib.internal.Share");
+ exc.invoke(loader, "com.falsepattern.lib.internal.asm.PreShare");
+ exc.invoke(loader, "com.falsepattern.lib.internal.FPLog");
+ exc.invoke(loader, "com.falsepattern.lib.internal.Tags");
+ exc.invoke(loader, "com.falsepattern.lib.internal.config.EarlyConfig");
+ exc.invoke(loader, "com.falsepattern.lib.internal.core.LowLevelCallMultiplexer");
+ } catch (Exception ignored) {}
+ PreShare.initDevState(((URLClassLoader)loader).findResource("net/minecraft/world/World.class") != null);
LetsEncryptHelper.replaceSSLContext();
LowLevelCallMultiplexer.rfbDetected();
- DependencyLoaderImpl.executeDependencyLoading(false);
+ DependencyLoaderImpl.executeDependencyLoading();
}
}
diff --git a/src/main/java/com/falsepattern/lib/internal/core/LowLevelCallMultiplexer.java b/src/main/java/com/falsepattern/lib/internal/core/LowLevelCallMultiplexer.java
index 4d01c85..6140e2b 100644
--- a/src/main/java/com/falsepattern/lib/internal/core/LowLevelCallMultiplexer.java
+++ b/src/main/java/com/falsepattern/lib/internal/core/LowLevelCallMultiplexer.java
@@ -29,8 +29,10 @@ import org.jetbrains.annotations.NotNull;
import net.minecraft.launchwrapper.Launch;
import java.net.URL;
+import java.net.URLClassLoader;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.Arrays;
import java.util.List;
@UtilityClass
@@ -64,21 +66,32 @@ public class LowLevelCallMultiplexer {
}
}
+ public static int javaMajorVersion() {
+ if (rfbDetected) {
+ return RFBLowLevel.javaMajorVersion();
+ } else {
+ return LaunchWrapperLowLevel.javaMajorVersion();
+ }
+ }
+
//Separate classes to avoid accidental classloading
- @SuppressWarnings("resource")
private static class RFBLowLevel {
static void addURLToClassPath(URL url) {
- RfbApiImpl.INSTANCE.compatClassLoader().addURL(url);
+ RfbApiImpl.INSTANCE.launchClassLoader().addURL(url);
}
static List getClassPathSources() {
- return RfbApiImpl.INSTANCE.compatClassLoader().getSources();
+ return Arrays.asList(((URLClassLoader)RfbApiImpl.INSTANCE.launchClassLoader()).getURLs());
}
static @NotNull Path gameDir() {
return RfbApiImpl.INSTANCE.gameDirectory();
}
+
+ static int javaMajorVersion() {
+ return RfbApiImpl.INSTANCE.javaMajorVersion();
+ }
}
private static class LaunchWrapperLowLevel {
@@ -93,5 +106,16 @@ public class LowLevelCallMultiplexer {
static @NotNull Path gameDir() {
return Launch.minecraftHome == null ? Paths.get(".") : Launch.minecraftHome.toPath();
}
+
+ static int javaMajorVersion() {
+ String version = System.getProperty("java.version");
+ if(version.startsWith("1.")) {
+ version = version.substring(2, 3);
+ } else {
+ int dot = version.indexOf(".");
+ if(dot != -1) { version = version.substring(0, dot); }
+ }
+ return Integer.parseInt(version);
+ }
}
}
diff --git a/src/main/java/com/falsepattern/lib/internal/impl/dependencies/DepRoot.java b/src/main/java/com/falsepattern/lib/internal/impl/dependencies/DepRoot.java
index a6a2237..fb98205 100644
--- a/src/main/java/com/falsepattern/lib/internal/impl/dependencies/DepRoot.java
+++ b/src/main/java/com/falsepattern/lib/internal/impl/dependencies/DepRoot.java
@@ -33,6 +33,10 @@ import java.util.List;
public class DepRoot {
private String source;
@Expose
+ private Integer minJava;
+ @Expose
+ private Integer maxJava;
+ @Expose
private List repositories;
@Expose
private Dependencies dependencies;
diff --git a/src/main/java/com/falsepattern/lib/internal/impl/dependencies/DependencyLoaderImpl.java b/src/main/java/com/falsepattern/lib/internal/impl/dependencies/DependencyLoaderImpl.java
index 9f15d40..40dc7b8 100644
--- a/src/main/java/com/falsepattern/lib/internal/impl/dependencies/DependencyLoaderImpl.java
+++ b/src/main/java/com/falsepattern/lib/internal/impl/dependencies/DependencyLoaderImpl.java
@@ -225,12 +225,12 @@ public class DependencyLoaderImpl {
}
}
- private static synchronized void addToClasspath(Path file) {
+ private static synchronized void addToClasspath(URL file) {
try {
- LowLevelCallMultiplexer.addURLToClassPath(file.toUri().toURL());
+ LowLevelCallMultiplexer.addURLToClassPath(file);
LOG.debug("Injected file {} into classpath!", file);
} catch (Exception e) {
- throw new RuntimeException("Failed to add library to classpath: " + file.toAbsolutePath(), e);
+ throw new RuntimeException("Failed to add library to classpath: " + file, e);
}
}
@@ -407,13 +407,13 @@ public class DependencyLoaderImpl {
private static boolean initialScan = false;
private static List> tasks;
- public static void executeDependencyLoading(boolean sideAware) {
+ public static void executeDependencyLoading() {
if (!initialScan) {
initialScan = true;
scanDeps();
}
- executeArtifactLoading(sideAware);
+ executeArtifactLoading();
}
private static void scanDeps() {
@@ -450,6 +450,7 @@ public class DependencyLoaderImpl {
} catch (IOException e) {
LOG.error("Could not write dependency scanner cache", e);
}
+ val javaVersion = LowLevelCallMultiplexer.javaMajorVersion();
val dependencySpecs = urls.stream().map((source) -> {
//Convert source to GSON json
try (val is = new BufferedInputStream(source.openStream())) {
@@ -468,6 +469,11 @@ public class DependencyLoaderImpl {
val gson = builder.create();
json.remove("identifier");
val root = gson.fromJson(json, DepRoot.class);
+ val minJ = root.minJava();
+ val maxJ = root.maxJava();
+ if (minJ != null && minJ > javaVersion || maxJ != null && maxJ < javaVersion) {
+ return null;
+ }
root.source(source.toString());
return root;
} catch (Exception e) {
@@ -562,8 +568,8 @@ public class DependencyLoaderImpl {
}
}
- private static void executeArtifactLoading(boolean sideAware) {
- val scopeSide = sideAware ? SideAwareAssistant.current() : new ScopeSide(DependencyScope.ALWAYS, DependencySide.COMMON);
+ private static void executeArtifactLoading() {
+ val scopeSide = SideAwareAssistant.current();
val iter = tasks.iterator();
val artifactMap = new HashMap();
while (iter.hasNext()) {
@@ -621,7 +627,6 @@ public class DependencyLoaderImpl {
}
jFrame.pack();
jFrame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
- jFrame.setVisible(true);
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
jFrame.setLocation(dim.width/2-jFrame.getSize().width/2, dim.height/2-jFrame.getSize().height/2);
} catch (Exception ignored) {
@@ -667,7 +672,14 @@ public class DependencyLoaderImpl {
@NotNull
private static Thread getVizThread(AtomicBoolean doViz, HashMap progresses, JFrame theFrame) {
val vizThread = new Thread(() -> {
+ int waitBeforeShowing = 100;
while (doViz.get()) {
+ if (waitBeforeShowing > 0) {
+ waitBeforeShowing--;
+ } else if (waitBeforeShowing == 0) {
+ theFrame.setVisible(true);
+ waitBeforeShowing = -1;
+ }
for (val progress : progresses.entrySet()) {
val task = progress.getKey();
val bar = progress.getValue();
@@ -825,11 +837,11 @@ public class DependencyLoaderImpl {
return false;
}
try {
- addToClasspath(file);
+ addToClasspath(file.toUri().toURL());
loadedLibraries.put(artifact, preferredVersion);
LOG.debug("Library {} successfully loaded from disk!", artifactLogName);
return true;
- } catch (RuntimeException e) {
+ } catch (Exception e) {
LOG.warn("Failed to load library {} from file! Re-downloading...", artifactLogName);
checkedDelete(file);
return false;
@@ -912,7 +924,7 @@ public class DependencyLoaderImpl {
}
loadedLibraries.put(artifact, preferredVersion);
loadedLibraryMods.put(artifact, loadingModId);
- addToClasspath(file);
+ addToClasspath(file.toUri().toURL());
return true;
}
}
diff --git a/src/main/resources/DEPENDENCIES.md b/src/main/resources/DEPENDENCIES.md
index e55e063..ae418f0 100644
--- a/src/main/resources/DEPENDENCIES.md
+++ b/src/main/resources/DEPENDENCIES.md
@@ -1,5 +1,5 @@
FalsePatternLib JSON dependency file example
-Version 1
+Version 2
An example JSON file that can be used to download dependencies using FalsePatternLib. This replaces the legacy
DependencyLoader api. This file needs to reside inside the META-INF directory.
@@ -7,6 +7,8 @@ DependencyLoader api. This file needs to reside inside the META-INF directory.
```json
{
"identifier": "falsepatternlib_dependencies",
+ "minJava": 8,
+ "maxJava": 8,
"repositories": [
"https://example.com/"
],
@@ -37,6 +39,12 @@ Explanation:
- `identifier`: The identifier of the json file. This must always be `falsepatternlib_dependencies` for the library
downloader
to recognize it.
+- `minJava`: The lowest java major version to load dependencies from this file for (inclusive). Can be omitted, in which case
+ it will load dependencies for any java versions below or equal maxJava.
+- `maxJava`: The highest java major version to load dependencies from this file for (inclusive). If omitted, it will load dependencies
+ for any java versions above or equal minJava.
+- If both `minJava` and `maxJava` are unset, dependencies from the file will be loaded regardless of java version.
+- If you want to load dependencies for multiple different java ranges, use multiple dependency jsons.
- `repositories`: A list of maven repositories to use when downloading dependencies. These are used in addition to the
default maven repositories. This is just a list of strings, each string being a https repository url.
Additionally, every jar with a dependencies json file inside of it is treated as a "jar in jar" maven repository.