diff options
Diffstat (limited to 'src')
10 files changed, 143 insertions, 35 deletions
diff --git a/src/main/java/moe/nea/modernjava/launch/FCPEntryPoint.java b/src/main/java/moe/nea/modernjava/launch/FCPEntryPoint.java index 3c32931..f7431ad 100644 --- a/src/main/java/moe/nea/modernjava/launch/FCPEntryPoint.java +++ b/src/main/java/moe/nea/modernjava/launch/FCPEntryPoint.java @@ -1,16 +1,25 @@ package moe.nea.modernjava.launch; +import moe.nea.modernjava.launch.live.FCPFixTweaker; import moe.nea.modernjava.launch.util.ClassLoaderManipulations; +import moe.nea.modernjava.launch.util.WellKnownBlackboard; import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin; import java.net.URI; import java.util.List; import java.util.Map; +import static moe.nea.modernjava.launch.util.PropertyNames.HAS_RELAUNCHED; +/** + * Global entrypoint for both the FML part of the relaunched (live) and the relaunching (relaunch) runs. Execution + * begins during static initialization to be as early as possible. There aren't any security implications, but especially + * on Windows it can be problematic if two processes try to open up the same file, so we try to avoid these conflicts. + * Also, it's just a faster launch. + */ @IFMLLoadingPlugin.Name("ModernJavaRelauncher") public class FCPEntryPoint implements IFMLLoadingPlugin { - static URI fileUri; + public static URI fileUri; static { try { @@ -18,9 +27,10 @@ public class FCPEntryPoint implements IFMLLoadingPlugin { } catch (Exception e) { throw new RuntimeException(e); } - if (System.getProperty("modernjava.hasrelaunched") == null) { + if (System.getProperty(HAS_RELAUNCHED) == null) { try { - Class.forName("moe.nea.modernjava.launch.FCPRelauncher").getMethod("relaunch").invoke(null); + Class.forName("moe.nea.modernjava.launch.relaunch.FCPRelauncher") + .getMethod("relaunch").invoke(null); } catch (Throwable t) { System.out.println("Failed to relaunch"); t.printStackTrace(); @@ -32,7 +42,7 @@ public class FCPEntryPoint implements IFMLLoadingPlugin { throw new RuntimeException(e); } List<String> tweakClasses = WellKnownBlackboard.tweakerNames(); - tweakClasses.add(FCPMixinAwareTweaker.class.getName()); + tweakClasses.add(FCPFixTweaker.class.getName()); } } diff --git a/src/main/java/moe/nea/modernjava/launch/FCPMixinAwareTweaker.java b/src/main/java/moe/nea/modernjava/launch/live/FCPFixTweaker.java index 585e943..a5bf648 100644 --- a/src/main/java/moe/nea/modernjava/launch/FCPMixinAwareTweaker.java +++ b/src/main/java/moe/nea/modernjava/launch/live/FCPFixTweaker.java @@ -1,12 +1,16 @@ -package moe.nea.modernjava.launch; +package moe.nea.modernjava.launch.live; +import moe.nea.modernjava.launch.transform.TransObjectHolderRef; import net.minecraft.launchwrapper.ITweaker; import net.minecraft.launchwrapper.LaunchClassLoader; import java.io.File; import java.util.List; -public class FCPMixinAwareTweaker implements ITweaker { +/** + * Tweaker class to inject {@link TransObjectHolderRef} + */ +public class FCPFixTweaker implements ITweaker { @Override public void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) { } diff --git a/src/main/java/moe/nea/modernjava/launch/FCPRelauncher.java b/src/main/java/moe/nea/modernjava/launch/relaunch/FCPRelauncher.java index ec27694..04fb0ea 100644 --- a/src/main/java/moe/nea/modernjava/launch/FCPRelauncher.java +++ b/src/main/java/moe/nea/modernjava/launch/relaunch/FCPRelauncher.java @@ -1,12 +1,12 @@ -package moe.nea.modernjava.launch; +package moe.nea.modernjava.launch.relaunch; -import net.minecraft.launchwrapper.Launch; +import moe.nea.modernjava.launch.util.PropertyNames; +import moe.nea.modernjava.launch.util.TextIoUtils; +import moe.nea.modernjava.launch.util.WellKnownBlackboard; import net.minecraftforge.fml.common.launcher.FMLTweaker; import net.minecraftforge.fml.nea.moe.modernjava.IAMFML; import java.io.File; -import java.io.FileDescriptor; -import java.io.FileOutputStream; import java.io.IOException; import java.lang.management.ManagementFactory; import java.util.ArrayList; @@ -14,14 +14,17 @@ import java.util.List; import java.util.Map; public class FCPRelauncher { - public static void relaunch() { + /** + * @return the original arguments, as passed to the main method. + */ + public static List<String> getOriginalArguments() { List<String> originalArgs = new ArrayList<>(); // Provided by FML // This is highly processed so there might be some arguments that become lost, but almost everything should be in here. // Namely non -- arguments get lost. I don't know any of these arguments that the vanilla launcher uses, so it should be fine? - // Also some tweakers are missing. But we can fix this. + // Also, some tweakers are missing. But we can fix this. Map<String, String> launchArgs = WellKnownBlackboard.launchArgs(); if ("UnknownFMLProfile".equals(launchArgs.get("--version"))) { launchArgs.remove("--version"); @@ -34,15 +37,23 @@ public class FCPRelauncher { originalArgs.add("--tweakClass"); originalArgs.add(FMLTweaker.class.getName()); - System.out.println("Reconstructed original minecraft arguments: " + originalArgs); + return originalArgs; + } + + public static File findJavaLauncher() { + return new File("/home/nea/.sdkman/candidates/java/16.0.2-tem/bin/java") + } + + public static void relaunch() { + + List<String> originalArgs = getOriginalArguments(); - String modernJavaPath = "/home/nea/.sdkman/candidates/java/16.0.2-tem/bin/java"; + File modernJavaPath = findJavaLauncher(); - String thisJarFile = FCPEntryPoint.class.getProtectionDomain().getCodeSource().getLocation().getFile(); - thisJarFile = "/home/nea/src/ModernJavaLauncher/target/build/libs/target.jar"; - System.out.println("Found modern java jar at: " + thisJarFile); + File agentFile; + agentFile = new File("/home/nea/src/ModernJavaLauncher/target/build/libs/target.jar"); System.out.println("Located modern minecraft at: " + modernJavaPath); @@ -58,19 +69,20 @@ public class FCPRelauncher { List<String> fullCommandLine = new ArrayList<>(); - fullCommandLine.add(modernJavaPath); + fullCommandLine.add(modernJavaPath.getAbsolutePath()); fullCommandLine.addAll(ManagementFactory.getRuntimeMXBean().getInputArguments()); - fullCommandLine.add("-Dmodernjava.hasrelaunched=true"); - fullCommandLine.add("-Dmodernjava.relaunchclasspath=" + thisJarFile + File.pathSeparator + ManagementFactory.getRuntimeMXBean().getClassPath()); + fullCommandLine.add("-D" + PropertyNames.HAS_RELAUNCHED + "=true"); + fullCommandLine.add("-D" + PropertyNames.RELAUNCH_CLASSPATH + "=" + agentFile.getAbsolutePath() + File.pathSeparator + ManagementFactory.getRuntimeMXBean().getClassPath()); fullCommandLine.add("--illegal-access=permit"); for (String open : moduleOpens) { fullCommandLine.add("--add-opens"); fullCommandLine.add(open); } - fullCommandLine.add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005"); - fullCommandLine.add("-javaagent:" + thisJarFile); + if (System.getProperty(PropertyNames.DEBUG_PORT) != null) + fullCommandLine.add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:" + System.getProperty(PropertyNames.DEBUG_PORT)); + fullCommandLine.add("-javaagent:" + agentFile); fullCommandLine.add("--add-modules=ALL-MODULE-PATH,ALL-SYSTEM,ALL-DEFAULT,java.sql"); - fullCommandLine.add("-Xbootclasspath/a:" + thisJarFile); + fullCommandLine.add("-Xbootclasspath/a:" + agentFile); fullCommandLine.add("moe.nea.modernjava.target.RelaunchEntryPoint"); fullCommandLine.addAll(originalArgs); @@ -84,11 +96,7 @@ public class FCPRelauncher { Process process = processBuilder.start(); exitCode = process.waitFor(); } finally { - try { - new FileOutputStream(FileDescriptor.out).flush(); - new FileOutputStream(FileDescriptor.err).flush(); - } catch (IOException ignored) { - } + TextIoUtils.flushStdIO(); } } catch (IOException | InterruptedException e) { throw new RuntimeException("Failed to relaunch with old java version", e); diff --git a/src/main/java/moe/nea/modernjava/launch/util/ClassLoaderManipulations.java b/src/main/java/moe/nea/modernjava/launch/util/ClassLoaderManipulations.java index 09f2368..6cc21e9 100644 --- a/src/main/java/moe/nea/modernjava/launch/util/ClassLoaderManipulations.java +++ b/src/main/java/moe/nea/modernjava/launch/util/ClassLoaderManipulations.java @@ -1,6 +1,7 @@ package moe.nea.modernjava.launch.util; import net.minecraft.launchwrapper.Launch; +import net.minecraft.launchwrapper.LaunchClassLoader; import java.io.File; import java.lang.reflect.Method; @@ -8,7 +9,10 @@ import java.net.MalformedURLException; import java.net.URL; public class ClassLoaderManipulations { - + /** + * Adds a File to the parent class loader of the launch class loader. Necessary if you want to/have to use + * {@link LaunchClassLoader#addClassLoaderExclusion(String)}. + */ public static void addToParentClassLoader(File file) { try { addToParentClassLoader(file.toURI().toURL()); @@ -17,6 +21,10 @@ public class ClassLoaderManipulations { } } + /** + * Adds a URL to the parent class loader of the launch class loader. Necessary if you want to/have to use + * {@link LaunchClassLoader#addClassLoaderExclusion(String)}. + */ public static void addToParentClassLoader(URL file) { try { Launch.classLoader.addURL(file); diff --git a/src/main/java/moe/nea/modernjava/launch/util/ReflectionUtils.java b/src/main/java/moe/nea/modernjava/launch/util/ObjectHolderRefCompanion.java index abc2364..15f9450 100644 --- a/src/main/java/moe/nea/modernjava/launch/util/ReflectionUtils.java +++ b/src/main/java/moe/nea/modernjava/launch/util/ObjectHolderRefCompanion.java @@ -1,10 +1,15 @@ package moe.nea.modernjava.launch.util; +import moe.nea.modernjava.launch.transform.TransObjectHolderRef; import sun.misc.Unsafe; import java.lang.reflect.Field; -public class ReflectionUtils { +/** + * A companion to my transformations from {@link TransObjectHolderRef} to avoid + * having to write all of this out in bytecode. + */ +public class ObjectHolderRefCompanion { private static Unsafe unsafe; static { @@ -17,10 +22,16 @@ public class ReflectionUtils { } } + /** + * A noop to have a jump target for the reflection factories. + */ public static void makeFieldWritable(Field f) { String s = "Doing nothing. We will use unsafe to set the value instead, if possible"; } + /** + * Write a value to a static final field. + */ public static void doFieldWrite(Field field, Object object) throws IllegalAccessException { if (unsafe == null) { field.set(null, object); diff --git a/src/main/java/moe/nea/modernjava/launch/util/PropertyNames.java b/src/main/java/moe/nea/modernjava/launch/util/PropertyNames.java new file mode 100644 index 0000000..8540dde --- /dev/null +++ b/src/main/java/moe/nea/modernjava/launch/util/PropertyNames.java @@ -0,0 +1,16 @@ +package moe.nea.modernjava.launch.util; + +public class PropertyNames { + /** + * Property set to indicate whether the java process was launched on the new java version. + */ + public static final String HAS_RELAUNCHED = "modernjava.hasrelaunched"; + /** + * Classpath to load after reloading. + */ + public static final String RELAUNCH_CLASSPATH = "modernjava.relaunchclasspath"; + /** + * Starts a debugger on the given port if present. + */ + public static final String DEBUG_PORT = "modernjava.debugport"; +} diff --git a/src/main/java/moe/nea/modernjava/launch/util/TextIoUtils.java b/src/main/java/moe/nea/modernjava/launch/util/TextIoUtils.java new file mode 100644 index 0000000..b7f82c0 --- /dev/null +++ b/src/main/java/moe/nea/modernjava/launch/util/TextIoUtils.java @@ -0,0 +1,22 @@ +package moe.nea.modernjava.launch.util; + +import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; + +public class TextIoUtils { + /** + * Flush out the standard IO, without closing it. Works even after {@link System#setOut(PrintStream)} or similar has been called + */ + public static void flushStdIO() { + try { + // These streams should not be closed. We just want to flush them out + //noinspection resource + new FileOutputStream(FileDescriptor.out).flush(); + //noinspection resource + new FileOutputStream(FileDescriptor.err).flush(); + } catch (IOException ignored) { + } + } +} diff --git a/src/main/java/moe/nea/modernjava/launch/WellKnownBlackboard.java b/src/main/java/moe/nea/modernjava/launch/util/WellKnownBlackboard.java index ee60b2a..967f531 100644 --- a/src/main/java/moe/nea/modernjava/launch/WellKnownBlackboard.java +++ b/src/main/java/moe/nea/modernjava/launch/util/WellKnownBlackboard.java @@ -1,16 +1,26 @@ -package moe.nea.modernjava.launch; +package moe.nea.modernjava.launch.util; import net.minecraft.launchwrapper.Launch; import java.util.List; import java.util.Map; +/** + * Contains references to the {@link Launch#blackboard black board} in one central spot to avoid misspelling. + */ @SuppressWarnings("unchecked") public class WellKnownBlackboard { + /** + * A list of tweaker class names yet to be executed. This does not include tweaker class names present in the current + * round of tweaking. + */ public static List<String> tweakerNames() { return (List<String>) Launch.blackboard.get("TweakClasses"); } + /** + * A map of arguments in the form of --prefixedKey to value. + */ public static Map<String, String> launchArgs() { return (Map<String, String>) Launch.blackboard.get("launchArgs"); } diff --git a/src/main/java/net/minecraftforge/fml/nea/moe/modernjava/IAMFML.java b/src/main/java/net/minecraftforge/fml/nea/moe/modernjava/IAMFML.java index 99ee7b0..d4d2844 100644 --- a/src/main/java/net/minecraftforge/fml/nea/moe/modernjava/IAMFML.java +++ b/src/main/java/net/minecraftforge/fml/nea/moe/modernjava/IAMFML.java @@ -1,7 +1,16 @@ package net.minecraftforge.fml.nea.moe.modernjava; +import net.minecraftforge.fml.relauncher.FMLSecurityManager; + +/** + * Class in a package starting with {@code net.minecraftforge.fml} in order to easily bypass the {@link FMLSecurityManager} + * which disallows calling {@link System#exit(int)}. + */ public class IAMFML { + /** + * Calls {@link System#exit(int)} + */ public static void shutdown(int code) { System.exit(code); } diff --git a/src/main/kotlin/moe/nea/modernjava/launch/transform/TransObjectHolderRef.kt b/src/main/kotlin/moe/nea/modernjava/launch/transform/TransObjectHolderRef.kt index 2fb4d04..2687dfc 100644 --- a/src/main/kotlin/moe/nea/modernjava/launch/transform/TransObjectHolderRef.kt +++ b/src/main/kotlin/moe/nea/modernjava/launch/transform/TransObjectHolderRef.kt @@ -5,14 +5,22 @@ import dev.falsehonesty.asmhelper.dsl.instructions.InsnListBuilder import dev.falsehonesty.asmhelper.dsl.instructions.InvokeType import dev.falsehonesty.asmhelper.dsl.modify import dev.falsehonesty.asmhelper.dsl.overwrite +import moe.nea.modernjava.launch.util.ObjectHolderRefCompanion import net.minecraft.launchwrapper.Launch import net.minecraft.launchwrapper.LaunchClassLoader import org.objectweb.asm.Opcodes import org.objectweb.asm.tree.AbstractInsnNode import org.objectweb.asm.tree.FieldInsnNode +/** + * Transform [net.minecraftforge.fml.common.registry.ObjectHolderRef] such that it does not make references to outdated + * Java Reflection Tools anymore + */ class TransObjectHolderRef : BaseClassTransformer() { override fun makeTransformers() { + /** + * Redirect the makeWritable call to [ObjectHolderRefCompanion] + */ overwrite { className = "net.minecraftforge.fml.common.registry.ObjectHolderRef" methodName = "makeWritable" @@ -22,13 +30,16 @@ class TransObjectHolderRef : BaseClassTransformer() { aload(0/* arg0 */) invoke( InvokeType.STATIC, - "moe/nea/modernjava/launch/util/ReflectionUtils", + "moe/nea/modernjava/launch/util/ObjectHolderRefCompanion", "makeFieldWritable", "(Ljava/lang/reflect/Field;)V" ) methodReturn() } } + /** + * Redirect the reflection calls to write a value to a static field in apply to [ObjectHolderRefCompanion] + */ modify("net/minecraftforge/fml/common/registry/ObjectHolderRef") { var end: AbstractInsnNode? = null var start: AbstractInsnNode? = null @@ -56,7 +67,7 @@ class TransObjectHolderRef : BaseClassTransformer() { getField("net/minecraftforge/fml/common/registry/ObjectHolderRef", "field", "Ljava/lang/reflect/Field;") aload(1 /*thing*/) invokeStatic( - "moe/nea/modernjava/launch/util/ReflectionUtils", + "moe/nea/modernjava/launch/util/ObjectHolderRefCompanion", "doFieldWrite", "(Ljava/lang/reflect/Field;Ljava/lang/Object;)V" ) @@ -86,8 +97,7 @@ class TransObjectHolderRef : BaseClassTransformer() { val classLoader: LaunchClassLoader = Launch.classLoader classLoader.addTransformerExclusion("kotlin.") - classLoader.addTransformerExclusion("dev.falsehonesty.asmhelper.") - classLoader.addTransformerExclusion("org.objenesis.") + classLoader.addTransformerExclusion("moe.nea.modernjava.dep.asmhelper.") classLoader.addTransformerExclusion(this.javaClass.name) setup(classLoader) |