From 0fb315abbe33f0bfc0338d296d4750075f8f00d5 Mon Sep 17 00:00:00 2001 From: Lassebq Date: Fri, 4 Oct 2024 00:53:16 +0300 Subject: [PATCH] Fullscreen fix. Update libraries in MultiMC.md --- MultiMC.md | 4 +- build.gradle | 12 +++ gradle/wrapper/gradle-wrapper.properties | 2 +- settings.gradle | 4 + .../launchwrapper/tweak/VanillaTweak.java | 2 + .../injection/legacy/ClassicCrashScreen.java | 6 ++ .../tweak/injection/legacy/LWJGLPatch.java | 50 ++++++++--- .../vanilla/OutOfFocusFullscreen.java | 85 +++++++++++++++++++ .../vanilla/VanillaTweakContext.java | 4 +- 9 files changed, 155 insertions(+), 14 deletions(-) create mode 100644 src/main/java/org/mcphackers/launchwrapper/tweak/injection/vanilla/OutOfFocusFullscreen.java diff --git a/MultiMC.md b/MultiMC.md index 063f259..1f1158c 100644 --- a/MultiMC.md +++ b/MultiMC.md @@ -33,10 +33,10 @@ This allows changing the Minecraft version in the instance without re-editing th }, { "name": "org.json:json:20240303", - "url": "https://mcphackers.github.io/libraries/" + "url": "https://repo1.maven.org/maven2/" }, { - "name": "org.mcphackers.rdi:rdi:1.0",, + "name": "org.mcphackers.rdi:rdi:1.0", "url": "https://maven.glass-launcher.net/releases/" } ], diff --git a/build.gradle b/build.gradle index ea13c45..aefdc04 100644 --- a/build.gradle +++ b/build.gradle @@ -60,8 +60,20 @@ allprojects { archives sourcesJar } + java { + toolchain { + languageVersion = JavaLanguageVersion.of(8) + } + } + compileJava { options.encoding = "UTF-8" + // needed to fix java.lang.NoSuchMethodError: java.nio.ByteBuffer.flip()Ljava/nio/ByteBuffer; + // but can't use it because of sun.misc.Unsafe + // If you are reading this, please use JDK 8 to compile + // if (JavaVersion.current().isJava9Compatible()) { + // options.release.set(8) + // } // Minecraft is mostly compatible with java 5 up until the version we support, so why not? sourceCompatibility = JavaVersion.VERSION_1_5 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 495da1d..b26381c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip diff --git a/settings.gradle b/settings.gradle index 303f0df..c912776 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,6 @@ +plugins { + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0' +} +rootProject.name = 'launchwrapper' include 'launchwrapper-fabric' // include 'launchwrapper-micromixin' \ No newline at end of file diff --git a/src/main/java/org/mcphackers/launchwrapper/tweak/VanillaTweak.java b/src/main/java/org/mcphackers/launchwrapper/tweak/VanillaTweak.java index 5c34b37..6c763c6 100644 --- a/src/main/java/org/mcphackers/launchwrapper/tweak/VanillaTweak.java +++ b/src/main/java/org/mcphackers/launchwrapper/tweak/VanillaTweak.java @@ -13,6 +13,7 @@ import org.mcphackers.launchwrapper.tweak.injection.legacy.ClassicCrashScreen; import org.mcphackers.launchwrapper.tweak.injection.vanilla.ChangeBrand; import org.mcphackers.launchwrapper.tweak.injection.vanilla.OneSixAssetsFix; +import org.mcphackers.launchwrapper.tweak.injection.vanilla.OutOfFocusFullscreen; import org.mcphackers.launchwrapper.tweak.injection.vanilla.VanillaTweakContext; public class VanillaTweak extends Tweak { @@ -27,6 +28,7 @@ public VanillaTweak(LaunchConfig launch) { public List getInjections() { return Arrays.asList( context, + new OutOfFocusFullscreen(context), new ClassicCrashScreen(context), new OneSixAssetsFix(context), new ChangeBrand() 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 0574301..f7e2a03 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 @@ -3,6 +3,9 @@ import static org.mcphackers.rdi.util.InsnHelper.*; import static org.objectweb.asm.Opcodes.*; +import java.util.ArrayList; +import java.util.List; + import org.mcphackers.launchwrapper.LaunchConfig; import org.mcphackers.launchwrapper.tweak.injection.InjectionWithContext; import org.mcphackers.launchwrapper.tweak.injection.MinecraftGetter; @@ -590,6 +593,9 @@ && compareInsn(insns[5], GETFIELD, null, null, "I")) { list = new InsnList(); list.add(new VarInsnNode(ALOAD, 0)); list.add(new FieldInsnNode(GETFIELD, screen.name, buttonsList.name, buttonsList.desc)); + list.add(new MethodInsnNode(INVOKEINTERFACE, "java/util/List", "clear", "()V")); + list.add(new VarInsnNode(ALOAD, 0)); + list.add(new FieldInsnNode(GETFIELD, screen.name, buttonsList.name, buttonsList.desc)); list.add(new TypeInsnNode(NEW, buttonType)); list.add(new InsnNode(DUP)); list.add(new InsnNode(ICONST_0)); diff --git a/src/main/java/org/mcphackers/launchwrapper/tweak/injection/legacy/LWJGLPatch.java b/src/main/java/org/mcphackers/launchwrapper/tweak/injection/legacy/LWJGLPatch.java index bec3719..34fbb51 100644 --- a/src/main/java/org/mcphackers/launchwrapper/tweak/injection/legacy/LWJGLPatch.java +++ b/src/main/java/org/mcphackers/launchwrapper/tweak/injection/legacy/LWJGLPatch.java @@ -26,6 +26,8 @@ */ public class LWJGLPatch extends InjectionWithContext { + private MethodNode tick; + public LWJGLPatch(LegacyTweakContext storage) { super(storage); } @@ -42,7 +44,8 @@ public boolean required() { @Override public boolean apply(ClassNodeSource source, LaunchConfig config) { - removeCanvas(getTickMethod(context.getRun())); + tick = getTickMethod(context.getRun()); + removeCanvas(tick); return displayPatch(context.getInit(), context.supportsResizing, source, config); } @@ -113,7 +116,6 @@ && compareInsn(insns[5], IFNE)) { } } - private MethodNode getTickMethod(MethodNode run) { ClassNode minecraft = context.getMinecraft(); FieldNode running = context.getIsRunning(); @@ -130,10 +132,8 @@ && compareInsn(insn, INVOKESPECIAL, minecraft.name, null, "()V")) { if(testedMethod != null) { AbstractInsnNode insn2 = testedMethod.instructions.getFirst(); while(insn2 != null) { - AbstractInsnNode[] insns = fill(insn2, 3); - if(compareInsn(insns[0], ALOAD) - && compareInsn(insns[1], ICONST_0) - && compareInsn(insns[2], PUTFIELD, minecraft.name, running.name, running.desc)) { + // tick method up to 1.12.2 contains this call + if(compareInsn(insn2, INVOKESTATIC, "org/lwjgl/opengl/Display", "isCloseRequested", "()Z")) { return testedMethod; } insn2 = nextInsn(insn2); @@ -191,7 +191,7 @@ && compareInsn(insns[1], DUP) && compareInsn(insns[2], ASTORE) && compareInsn(insns[3], GETFIELD, minecraft.name, null, "Ljava/awt/Canvas;") && compareInsn(insns[4], IFNULL)) { - // Required for in-20100131-2. Has this weird bytecode to ASTORE this instance to another var + // Required for in-20100131-2. Has weird bytecode to ASTORE this instance to another var thisIndex = ((VarInsnNode) insns[2]).var; canvasName = ((FieldInsnNode) insns[3]).name; ifNoCanvas = (JumpInsnNode) insns[4]; @@ -317,8 +317,9 @@ && compareInsn(insns[1], INVOKESTATIC, "org/lwjgl/opengl/Display", "setFullscree insert.add(new MethodInsnNode(INVOKESTATIC, "org/lwjgl/opengl/Display", "setTitle", "(Ljava/lang/String;)V")); insnList.insertBefore(insnList.getFirst(), insert); } - + if(context.fullscreenField != null) { + MethodNode toggleFullscreen = null; methodLoop: for(MethodNode m : minecraft.methods) { AbstractInsnNode insn2 = m.instructions.getFirst(); @@ -363,7 +364,7 @@ && compareInsn(insns3[6], INVOKESPECIAL, "org/lwjgl/opengl/DisplayMode", " && compareInsn(insns3[7], INVOKESTATIC, "org/lwjgl/opengl/Display", "setDisplayMode", "(Lorg/lwjgl/opengl/DisplayMode;)V")) { m.instructions.set(insns3[3], new FieldInsnNode(GETFIELD, minecraft.name, context.defaultWidth.name, context.defaultWidth.desc)); m.instructions.set(insns3[5], new FieldInsnNode(GETFIELD, minecraft.name, context.defaultHeight.name, context.defaultHeight.desc)); - break methodLoop; + break; } else { JumpInsnNode jump = (JumpInsnNode) insns2[0]; LabelNode newLabel = new LabelNode(); @@ -379,11 +380,40 @@ && compareInsn(insns3[6], INVOKESPECIAL, "org/lwjgl/opengl/DisplayMode", " insert.add(new MethodInsnNode(INVOKESPECIAL, "org/lwjgl/opengl/DisplayMode", "", "(II)V")); insert.add(new MethodInsnNode(INVOKESTATIC, "org/lwjgl/opengl/Display", "setDisplayMode", "(Lorg/lwjgl/opengl/DisplayMode;)V")); m.instructions.insert(insns2[3], insert); - break methodLoop; + break; } } insn2 = nextInsn(insn2); } + insn2 = m.instructions.getFirst(); + while(insn2 != null) { + AbstractInsnNode[] insns2 = fill(insn2, 4); + if(compareInsn(insns2[0], INVOKESTATIC, "org/lwjgl/opengl/Display", "setFullscreen", "(Z)V") + && compareInsn(insns2[1], INVOKESTATIC, "org/lwjgl/opengl/Display", "update", "()V") + && compareInsn(insns2[2], LDC, 1000L) + && compareInsn(insns2[3], INVOKESTATIC, "java/lang/Thread", "sleep", "(J)V")) { + // Removes fullscreen delay + m.instructions.remove(insns2[2]); + m.instructions.remove(insns2[3]); + toggleFullscreen = m; + } + + insn2 = nextInsn(insn2); + } + } + if(toggleFullscreen != null) { + for(AbstractInsnNode insn2 = tick.instructions.getFirst(); insn2 != null; insn2 = nextInsn(insn2)) { + AbstractInsnNode[] insns2 = fill(insn2, 7); + if(compareInsn(insns2[0], INVOKESTATIC, "org/lwjgl/opengl/Display", "isActive", "()Z") + && compareInsn(insns2[1], IFNE) + && compareInsn(insns2[2], ALOAD) + && compareInsn(insns2[3], GETFIELD, minecraft.name, context.fullscreenField.name, context.fullscreenField.desc) + && compareInsn(insns2[4], IFEQ) + && compareInsn(insns2[5], ALOAD) + && compareInsn(insns2[6], INVOKEVIRTUAL, minecraft.name, toggleFullscreen.name, toggleFullscreen.desc)) { + tick.instructions.set(insn2, new InsnNode(ICONST_1)); + } + } } } diff --git a/src/main/java/org/mcphackers/launchwrapper/tweak/injection/vanilla/OutOfFocusFullscreen.java b/src/main/java/org/mcphackers/launchwrapper/tweak/injection/vanilla/OutOfFocusFullscreen.java new file mode 100644 index 0000000..07b0cc9 --- /dev/null +++ b/src/main/java/org/mcphackers/launchwrapper/tweak/injection/vanilla/OutOfFocusFullscreen.java @@ -0,0 +1,85 @@ +package org.mcphackers.launchwrapper.tweak.injection.vanilla; + +import static org.mcphackers.rdi.util.InsnHelper.*; +import static org.objectweb.asm.Opcodes.*; + +import org.mcphackers.launchwrapper.LaunchConfig; +import org.mcphackers.launchwrapper.tweak.injection.InjectionWithContext; +import org.mcphackers.launchwrapper.tweak.injection.MinecraftGetter; +import org.mcphackers.launchwrapper.util.ClassNodeSource; +import org.mcphackers.rdi.util.NodeHelper; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; + +/** + * Part of LWJGLPatch, but for 1.6+ without need for deAWT + */ +public class OutOfFocusFullscreen extends InjectionWithContext { + + public OutOfFocusFullscreen(MinecraftGetter context) { + super(context); + } + + @Override + public String name() { + return "Fullscreen fix"; + } + + @Override + public boolean required() { + return false; + } + + private MethodNode getTickMethod(MethodNode run) { + ClassNode minecraft = context.getMinecraft(); + FieldNode running = context.getIsRunning(); + if(running == null) { + return run; + } + AbstractInsnNode insn = run.instructions.getFirst(); + while(insn != null) { + if(compareInsn(insn.getPrevious(), ALOAD) + && compareInsn(insn, INVOKESPECIAL, minecraft.name, null, "()V")) { + MethodInsnNode invoke = (MethodInsnNode) insn; + MethodNode testedMethod = NodeHelper.getMethod(minecraft, invoke.name, invoke.desc); + if(testedMethod != null) { + AbstractInsnNode insn2 = testedMethod.instructions.getFirst(); + while(insn2 != null) { + // tick method up to 1.12.2 contains this call + if(compareInsn(insn2, INVOKESTATIC, "org/lwjgl/opengl/Display", "isCloseRequested", "()Z")) { + return testedMethod; + } + insn2 = nextInsn(insn2); + } + } + } + insn = nextInsn(insn); + } + return run; + } + + @Override + public boolean apply(ClassNodeSource source, LaunchConfig config) { + ClassNode minecraft = context.getMinecraft(); + MethodNode tick = getTickMethod(context.getRun()); + for(AbstractInsnNode insn = tick.instructions.getFirst(); insn != null; insn = nextInsn(insn)) { + AbstractInsnNode[] insns2 = fill(insn, 7); + if(compareInsn(insns2[0], INVOKESTATIC, "org/lwjgl/opengl/Display", "isActive", "()Z") + && compareInsn(insns2[1], IFNE) + && compareInsn(insns2[2], ALOAD) + && compareInsn(insns2[3], GETFIELD, minecraft.name, null, "Z") + && compareInsn(insns2[4], IFEQ) + && compareInsn(insns2[5], ALOAD) + && compareInsn(insns2[6], INVOKEVIRTUAL, minecraft.name, null, "()V")) { + tick.instructions.set(insn, new InsnNode(ICONST_1)); + return true; + } + } + return false; + } + +} diff --git a/src/main/java/org/mcphackers/launchwrapper/tweak/injection/vanilla/VanillaTweakContext.java b/src/main/java/org/mcphackers/launchwrapper/tweak/injection/vanilla/VanillaTweakContext.java index a22c5a1..bfc00a9 100644 --- a/src/main/java/org/mcphackers/launchwrapper/tweak/injection/vanilla/VanillaTweakContext.java +++ b/src/main/java/org/mcphackers/launchwrapper/tweak/injection/vanilla/VanillaTweakContext.java @@ -5,7 +5,9 @@ import java.io.File; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.mcphackers.launchwrapper.LaunchConfig; import org.mcphackers.launchwrapper.tweak.VanillaTweak; @@ -27,7 +29,7 @@ public class VanillaTweakContext implements Injection, MinecraftGetter { public ClassNode minecraft; public MethodNode run; public FieldNode running; - public List availableParameters = new ArrayList(); + public Set availableParameters = new HashSet(); public String[] args; public ClassNode getMinecraft() {