diff --git a/build.gradle b/build.gradle index ae2609e..e58e84e 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ dependencies { implementation "org.ow2.asm:asm:${project.asm_version}" implementation "org.ow2.asm:asm-util:${project.asm_version}" implementation "org.ow2.asm:asm-tree:${project.asm_version}" - implementation "org.json:json:20230311" + implementation "org.json:json:20240303" // I'll bring discord RPC support later, when I have an environment to compile natives testRuntimeOnly('org.junit.platform:junit-platform-launcher:1.5.2') @@ -41,16 +41,12 @@ allprojects { } repositories { - mavenLocal() maven { url "https://libraries.minecraft.net/" } maven { url "https://maven.glass-launcher.net/releases" } - maven { - url "https://mcphackers.github.io/libraries/" - } mavenCentral() } diff --git a/src/main/java/org/mcphackers/launchwrapper/Launch.java b/src/main/java/org/mcphackers/launchwrapper/Launch.java index 43aad15..a0a6ddc 100644 --- a/src/main/java/org/mcphackers/launchwrapper/Launch.java +++ b/src/main/java/org/mcphackers/launchwrapper/Launch.java @@ -1,6 +1,7 @@ package org.mcphackers.launchwrapper; import org.mcphackers.launchwrapper.loader.LaunchClassLoader; +import org.mcphackers.launchwrapper.target.LaunchTarget; import org.mcphackers.launchwrapper.tweak.Tweak; public class Launch { @@ -35,7 +36,7 @@ public void launch() { LaunchClassLoader loader = getLoader(); Tweak mainTweak = getTweak(); if(mainTweak == null) { - System.err.println("Could not find launch target"); + LOGGER.logErr("No suitable tweak found. Is Minecraft on classpath?"); return; } mainTweak.prepare(loader); @@ -45,9 +46,14 @@ public void launch() { setupDiscordRPC(); } loader.setLoaderTweak(mainTweak.getLoaderTweak()); - mainTweak.getLaunchTarget().launch(loader); + LaunchTarget target = mainTweak.getLaunchTarget(); + if(target != null) { + target.launch(loader); + } else { + LOGGER.logErr("Could not find launch target"); + } } else { - System.err.println("Tweak could not be applied"); + LOGGER.logErr("Tweak could not be applied"); } } @@ -78,6 +84,10 @@ public void log(String format, Object... args) { System.out.println("[LaunchWrapper] " + String.format(format, args)); } + public void logErr(String format, Object... args) { + System.err.println("[LaunchWrapper] " + String.format(format, args)); + } + public void logDebug(String format, Object... args) { if(!DEBUG) { return; diff --git a/src/main/java/org/mcphackers/launchwrapper/loader/LaunchClassLoader.java b/src/main/java/org/mcphackers/launchwrapper/loader/LaunchClassLoader.java index a8a58e1..7891442 100644 --- a/src/main/java/org/mcphackers/launchwrapper/loader/LaunchClassLoader.java +++ b/src/main/java/org/mcphackers/launchwrapper/loader/LaunchClassLoader.java @@ -94,6 +94,15 @@ private URL getOverridenResourceURL(String name) { return null; } + @Override + public URL[] getURLs() { + if(parent instanceof URLClassLoader) { + return ((URLClassLoader)parent).getURLs(); + } + //TODO get classpath list on modern java + return super.getURLs(); + } + public Enumeration findResources(String name) throws IOException { return parent.getResources(name); } diff --git a/src/main/java/org/mcphackers/launchwrapper/tweak/ForgeTweak.java b/src/main/java/org/mcphackers/launchwrapper/tweak/ForgeTweak.java new file mode 100644 index 0000000..d9d7ab9 --- /dev/null +++ b/src/main/java/org/mcphackers/launchwrapper/tweak/ForgeTweak.java @@ -0,0 +1,40 @@ +package org.mcphackers.launchwrapper.tweak; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.mcphackers.launchwrapper.LaunchConfig; +import org.mcphackers.launchwrapper.loader.LaunchClassLoader; +import org.mcphackers.launchwrapper.tweak.injection.Injection; +import org.mcphackers.launchwrapper.tweak.injection.legacy.AddMain; +import org.mcphackers.launchwrapper.tweak.injection.legacy.ClassicCrashScreen; +import org.mcphackers.launchwrapper.tweak.injection.legacy.FixClassicSession; +import org.mcphackers.launchwrapper.tweak.injection.legacy.FixGrayScreen; +import org.mcphackers.launchwrapper.tweak.injection.legacy.FixShutdown; +import org.mcphackers.launchwrapper.tweak.injection.legacy.FixSplashScreen; +import org.mcphackers.launchwrapper.tweak.injection.legacy.ForgeVersionCheck; +import org.mcphackers.launchwrapper.tweak.injection.legacy.IndevSaving; +import org.mcphackers.launchwrapper.tweak.injection.legacy.LWJGLPatch; +import org.mcphackers.launchwrapper.tweak.injection.legacy.LegacyInit; +import org.mcphackers.launchwrapper.tweak.injection.legacy.OptionsLoadFix; +import org.mcphackers.launchwrapper.tweak.injection.legacy.ReplaceGameDir; +import org.mcphackers.launchwrapper.tweak.injection.legacy.UnlicensedCopyText; +import org.mcphackers.launchwrapper.tweak.injection.vanilla.ChangeBrand; + +public class ForgeTweak extends LegacyTweak { + + public ForgeTweak(LaunchConfig config) { + super(config); + } + + public List getInjections() { + List list = new ArrayList(); + list.addAll(super.getInjections()); + list.add(new ForgeVersionCheck()); + return list; + } + +} diff --git a/src/main/java/org/mcphackers/launchwrapper/tweak/Tweak.java b/src/main/java/org/mcphackers/launchwrapper/tweak/Tweak.java index 8325988..8e06a06 100644 --- a/src/main/java/org/mcphackers/launchwrapper/tweak/Tweak.java +++ b/src/main/java/org/mcphackers/launchwrapper/tweak/Tweak.java @@ -62,26 +62,29 @@ public final boolean transform(ClassNodeSource source) { public abstract ClassLoaderTweak getLoaderTweak(); public abstract LaunchTarget getLaunchTarget(); + + public static Tweak forClass(ClassNodeSource source, LaunchConfig launch, String clazz) { + try { + try { + return (Tweak)Class.forName(clazz) + .getConstructor(LaunchConfig.class, Tweak.class) + .newInstance(launch, getDefault(source, launch)); + } catch (NoSuchMethodException e) { + return (Tweak)Class.forName(clazz) + .getConstructor(LaunchConfig.class) + .newInstance(launch); + } + } catch (ClassNotFoundException e) { + return null; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } public static Tweak get(ClassNodeSource classLoader, LaunchConfig launch) { if(launch.tweakClass.get() != null) { - try { - try { - // Instantiate custom tweak if it's present on classpath; - return (Tweak)Class.forName(launch.tweakClass.get()) - .getConstructor(LaunchConfig.class, Tweak.class) - .newInstance(launch, getDefault(classLoader, launch)); - } catch (NoSuchMethodException e) { - return (Tweak)Class.forName(launch.tweakClass.get()) - .getConstructor(LaunchConfig.class) - .newInstance(launch); - } - } catch (ClassNotFoundException e) { - return null; - } catch (Exception e) { - e.printStackTrace(); - return null; - } + return forClass(classLoader, launch, launch.tweakClass.get()); } return getDefault(classLoader, launch); } diff --git a/src/main/java/org/mcphackers/launchwrapper/tweak/injection/legacy/ClassicCrashScreen.java b/src/main/java/org/mcphackers/launchwrapper/tweak/injection/legacy/ClassicCrashScreen.java index 4f01706..2f6e63d 100644 --- a/src/main/java/org/mcphackers/launchwrapper/tweak/injection/legacy/ClassicCrashScreen.java +++ b/src/main/java/org/mcphackers/launchwrapper/tweak/injection/legacy/ClassicCrashScreen.java @@ -49,7 +49,7 @@ public boolean required() { @Override public boolean apply(ClassNodeSource source, LaunchConfig config) { - if (context.run == null) { + if(context.run == null) { return false; } AbstractInsnNode insn1 = context.run.instructions.getFirst(); @@ -58,73 +58,70 @@ public boolean apply(ClassNodeSource source, LaunchConfig config) { LabelNode start = null; AbstractInsnNode end = null; TryCatchBlockNode afterCatch = null; - while (insn1 != null) { + while(insn1 != null) { AbstractInsnNode[] insns1 = fill(insn1, 6); - if (compareInsn(insns1[0], ALOAD, 0) - && compareInsn(insns1[1], GETFIELD, context.minecraft.name, context.running.name, - context.running.desc) - && compareInsn(insns1[2], IFEQ) - && compareInsn(insns1[3], ALOAD, 0) - && compareInsn(insns1[4], GETFIELD, context.minecraft.name, null, - "L" + context.minecraftApplet.name + ";") - && compareInsn(insns1[5], IFNULL)) { + if(compareInsn(insns1[0], ALOAD, 0) + && compareInsn(insns1[1], GETFIELD, context.minecraft.name, context.running.name, context.running.desc) + && compareInsn(insns1[2], IFEQ) + && compareInsn(insns1[3], ALOAD, 0) + && compareInsn(insns1[4], GETFIELD, context.minecraft.name, null, "L" + context.minecraftApplet.name + ";") + && compareInsn(insns1[5], IFNULL)) { start = new LabelNode(); context.run.instructions.insertBefore(insn1, start); JumpInsnNode jmp = (JumpInsnNode) insns1[2]; end = previousInsn(jmp.label); // GOTO outside of loop // end = previousInsn(end); // GOTO to the beggining of loop - for (TryCatchBlockNode tryCatch : context.run.tryCatchBlocks) { - if (afterCatch == null && tryCatch.type != null && !tryCatch.type.startsWith("java/lang/")) { + for(TryCatchBlockNode tryCatch : context.run.tryCatchBlocks) { + if(afterCatch == null && tryCatch.type != null && !tryCatch.type.startsWith("java/lang/")) { afterCatch = tryCatch; } - // if ("java/lang/Throwable".equals(tryCatch.type)) { AbstractInsnNode testInsn = nextInsn(tryCatch.handler); - while (tryCatch.end != testInsn && testInsn != null) { + while(tryCatch.end != testInsn && testInsn != null) { testInsn = nextInsn(testInsn); - if (compareInsn(testInsn, ACONST_NULL) && compareInsn(nextInsn(testInsn), PUTFIELD)) { + if(compareInsn(testInsn, ACONST_NULL) + && compareInsn(nextInsn(testInsn), PUTFIELD)) { FieldInsnNode putfield = (FieldInsnNode) nextInsn(testInsn); fieldName = putfield.name; fieldDesc = putfield.desc; } } - // } } } insn1 = nextInsn(insn1); } - if (start == null || end == null) { + if(start == null || end == null) { return false; } - if (fieldDesc == null || fieldName == null) { + if(fieldDesc == null || fieldName == null) { return false; } MethodNode setWorld = null; - for (MethodNode m : context.minecraft.methods) { - if (m.desc.equals("(" + fieldDesc + ")V")) { + for(MethodNode m : context.minecraft.methods) { + if(m.desc.equals("(" + fieldDesc + ")V")) { setWorld = m; break; } } - if (setWorld == null) { + if(setWorld == null) { return false; } ClassNode errScreen = null; MethodNode openScreen = null; - for (MethodNode m : context.minecraft.methods) { - if (m.desc.equals("()V")) { + for(MethodNode m : context.minecraft.methods) { + if(m.desc.equals("()V")) { AbstractInsnNode insn = m.instructions.getFirst(); - if (insn != null && insn.getOpcode() == -1) { + if(insn != null && insn.getOpcode() == -1) { insn = nextInsn(insn); } - if (!compareInsn(insn, INVOKESTATIC, "org/lwjgl/opengl/Display", "isActive", "()Z")) { + if(!compareInsn(insn, INVOKESTATIC, "org/lwjgl/opengl/Display", "isActive", "()Z")) { continue; } AbstractInsnNode insn2 = insn; - while (insn2 != null) { + while(insn2 != null) { AbstractInsnNode[] insns2 = fill(insn2, 3); - if (compareInsn(insns2[0], ALOAD, 0) - && compareInsn(insns2[1], ACONST_NULL) - && compareInsn(insns2[2], INVOKEVIRTUAL, context.minecraft.name, null, null)) { + if(compareInsn(insns2[0], ALOAD, 0) + && compareInsn(insns2[1], ACONST_NULL) + && compareInsn(insns2[2], INVOKEVIRTUAL, context.minecraft.name, null, null)) { MethodInsnNode invoke = (MethodInsnNode) insns2[2]; openScreen = NodeHelper.getMethod(context.minecraft, invoke.name, invoke.desc); break; @@ -134,40 +131,40 @@ && compareInsn(insns2[2], INVOKEVIRTUAL, context.minecraft.name, null, null)) { break; } } - if (openScreen == null) { + if(openScreen == null) { return false; } AbstractInsnNode insn = openScreen.instructions.getFirst(); - while (insn != null) { - if (insn.getOpcode() == INSTANCEOF) { + while(insn != null) { + if(insn.getOpcode() == INSTANCEOF) { break; } insn = nextInsn(insn); } - if (insn == null) { + if(insn == null) { return false; } errScreen = source.getClass(((TypeInsnNode) insn).desc); - if (errScreen == null) { + if(errScreen == null) { return false; } MethodNode init = NodeHelper.getMethod(errScreen, "", "(Ljava/lang/String;Ljava/lang/String;)V"); - if (init == null) { + if(init == null) { MethodNode newInit = new MethodNode(ACC_PUBLIC, "", "(Ljava/lang/String;Ljava/lang/String;)V", null, null); InsnList insnList = newInit.instructions; insnList.add(new VarInsnNode(ALOAD, 0)); insnList.add(new MethodInsnNode(INVOKESPECIAL, errScreen.superName, "", "()V")); int c = 1; - for (FieldNode f : errScreen.fields) { - if (!f.desc.equals("Ljava/lang/String;")) { + for(FieldNode f : errScreen.fields) { + if(!f.desc.equals("Ljava/lang/String;")) { continue; } insnList.add(new VarInsnNode(ALOAD, 0)); insnList.add(new VarInsnNode(ALOAD, c)); insnList.add(new FieldInsnNode(PUTFIELD, errScreen.name, f.name, f.desc)); - if (c == 2) { + if(c == 2) { break; } c++; diff --git a/src/main/java/org/mcphackers/launchwrapper/tweak/injection/legacy/FixShutdown.java b/src/main/java/org/mcphackers/launchwrapper/tweak/injection/legacy/FixShutdown.java index e7d8846..8b613a2 100644 --- a/src/main/java/org/mcphackers/launchwrapper/tweak/injection/legacy/FixShutdown.java +++ b/src/main/java/org/mcphackers/launchwrapper/tweak/injection/legacy/FixShutdown.java @@ -9,18 +9,11 @@ import org.mcphackers.rdi.util.NodeHelper; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.FieldInsnNode; -import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.InsnNode; -import org.objectweb.asm.tree.JumpInsnNode; -import org.objectweb.asm.tree.LabelNode; -import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.TryCatchBlockNode; -import org.objectweb.asm.tree.TypeInsnNode; import org.objectweb.asm.tree.VarInsnNode; public class FixShutdown extends InjectionWithContext { @@ -94,7 +87,6 @@ && compareInsn(insns2[1], INVOKESTATIC, "java/lang/System", "exit", "(I)V")) { insert.add(new MethodInsnNode(INVOKESTATIC, "java/lang/System", "exit", "(I)V")); destroy.instructions.insert(insn1, insert); b = true; - // tweakInfo("Shutdown patch"); } } } @@ -126,7 +118,6 @@ && compareInsn(insns2[2], INVOKEVIRTUAL, context.minecraft.name, null, null)) { if(Type.getReturnType(invoke.desc).getSort() == Type.VOID) { addTryCatch(destroy, insns2[0], insns2[2], "java/lang/Throwable"); b = true; - // tweakInfo("SoundManager shutdown"); break; } } diff --git a/src/main/java/org/mcphackers/launchwrapper/tweak/injection/legacy/ForgeVersionCheck.java b/src/main/java/org/mcphackers/launchwrapper/tweak/injection/legacy/ForgeVersionCheck.java new file mode 100644 index 0000000..da748dd --- /dev/null +++ b/src/main/java/org/mcphackers/launchwrapper/tweak/injection/legacy/ForgeVersionCheck.java @@ -0,0 +1,40 @@ +package org.mcphackers.launchwrapper.tweak.injection.legacy; + +import static org.objectweb.asm.Opcodes.*; + +import org.mcphackers.launchwrapper.LaunchConfig; +import org.mcphackers.launchwrapper.tweak.injection.Injection; +import org.mcphackers.launchwrapper.util.ClassNodeSource; +import org.mcphackers.rdi.util.NodeHelper; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.MethodNode; + +public class ForgeVersionCheck implements Injection { + + @Override + public String name() { + return "Forge mc version check"; + } + + @Override + public boolean required() { + return false; + } + + @Override + public boolean apply(ClassNodeSource source, LaunchConfig config) { + ClassNode forgeClient = source.getClass("forge/MinecraftForgeClient"); + if(forgeClient == null) { + return false; + } + MethodNode checkVersion = NodeHelper.getMethod(forgeClient, "checkMinecraftVersion", "(Ljava/lang/String;Ljava/lang/String;)V"); + if(checkVersion == null) { + return false; + } + checkVersion.instructions.insert(new InsnNode(RETURN)); + source.overrideClass(forgeClient); + return true; + } + +} diff --git a/src/test/java/org/mcphackers/launchwrapper/test/DebugLaunch.java b/src/test/java/org/mcphackers/launchwrapper/test/DebugLaunch.java index 7d4edc7..fd829f4 100644 --- a/src/test/java/org/mcphackers/launchwrapper/test/DebugLaunch.java +++ b/src/test/java/org/mcphackers/launchwrapper/test/DebugLaunch.java @@ -15,8 +15,6 @@ public static void main(String[] args) { System.setProperty("java.library.path", new File(config.gameDir.get(), "natives").getAbsolutePath()); } System.setProperty("launchwrapper.log", "true"); - config.session.set("-"); - config.accessToken.set("-"); Launch launch = Launch.create(config); launch.getLoader().setDebugOutput(new File("./debug")); launch.launch();