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.