diff --git a/README.md b/README.md index cc72e30..a9dfa61 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ LaunchWrapper is bundled in [BetterJSONs](https://github.com/MCPHackers/BetterJS - Online mode authentication fix - LaunchWrapper works with Risugami's Modloader so long as you're using Java 8 - Built-in [Modloader Fix](https://github.com/coffeenotfound/ModloaderFix-b1.7.3) +- Drop-in replacement for [LegacyLauncher (aka net.minecraft.launchwrapper)](https://github.com/Mojang/LegacyLauncher) - Allows changing game directory in versions before 1.6 - Makes save slots in classic and indev functional and saves to `.minecraft/levels` directory - Adds ability to launch classic and pre-classic at custom resolution or in fullscreen diff --git a/build.gradle b/build.gradle index 73ca2d7..cdd09bf 100644 --- a/build.gradle +++ b/build.gradle @@ -42,12 +42,13 @@ subprojects { dependencies { implementation rootProject + runtimeOnly rootProject.sourceSets.test.output } } allprojects { apply plugin: 'java' - apply plugin: 'maven-publish' + apply plugin: 'maven-publish' repositories { maven { @@ -128,4 +129,4 @@ allprojects { } } } -} \ No newline at end of file +} diff --git a/src/main/java/org/mcphackers/launchwrapper/tweak/LegacyTweak.java b/src/main/java/org/mcphackers/launchwrapper/tweak/LegacyTweak.java index f96ad15..a64ab33 100644 --- a/src/main/java/org/mcphackers/launchwrapper/tweak/LegacyTweak.java +++ b/src/main/java/org/mcphackers/launchwrapper/tweak/LegacyTweak.java @@ -38,6 +38,7 @@ import org.mcphackers.launchwrapper.tweak.injection.legacy.ReplaceGameDir; import org.mcphackers.launchwrapper.tweak.injection.legacy.UnlicensedCopyText; import org.mcphackers.launchwrapper.tweak.injection.vanilla.ChangeBrand; +import org.mcphackers.launchwrapper.tweak.injection.vanilla.OutOfFocusFullscreen; import org.mcphackers.launchwrapper.util.UnsafeUtils; import org.mcphackers.launchwrapper.util.Util; import org.mcphackers.rdi.util.NodeHelper; @@ -74,6 +75,7 @@ public List getInjections() { new IndevSaving(context), new BitDepthFix(context), new LWJGLPatch(context), + new OutOfFocusFullscreen(context), new MouseFix(context), new ReplaceGameDir(context), new OptionsLoadFix(context), diff --git a/src/main/java/org/mcphackers/launchwrapper/tweak/injection/legacy/AddMain.java b/src/main/java/org/mcphackers/launchwrapper/tweak/injection/legacy/AddMain.java index f382c24..e2aa77b 100644 --- a/src/main/java/org/mcphackers/launchwrapper/tweak/injection/legacy/AddMain.java +++ b/src/main/java/org/mcphackers/launchwrapper/tweak/injection/legacy/AddMain.java @@ -3,6 +3,7 @@ import static org.mcphackers.rdi.util.InsnHelper.*; import static org.objectweb.asm.Opcodes.*; +import org.mcphackers.launchwrapper.Launch; import org.mcphackers.launchwrapper.LaunchConfig; import org.mcphackers.launchwrapper.tweak.injection.InjectionWithContext; import org.mcphackers.launchwrapper.util.ClassNodeSource; @@ -127,7 +128,6 @@ protected MethodNode getMain(ClassNodeSource source, LaunchConfig config) { final int appletIndex = 1; final int frameIndex = 2; final int mcIndex = 3; - final int threadIndex = 4; final String listenerClass = "org/mcphackers/launchwrapper/inject/WindowListener"; @@ -214,14 +214,9 @@ protected MethodNode getMain(ClassNodeSource source, LaunchConfig config) { insns.add(new FieldInsnNode(PUTFIELD, minecraft.name, context.appletMode.name, context.appletMode.desc)); } if(config.lwjglFrame.get()) { - insns.add(new TypeInsnNode(NEW, "java/lang/Thread")); - insns.add(new InsnNode(DUP)); insns.add(new VarInsnNode(ALOAD, mcIndex)); - insns.add(new LdcInsnNode("Minecraft main thread")); - insns.add(new MethodInsnNode(INVOKESPECIAL, "java/lang/Thread", "", "(Ljava/lang/Runnable;Ljava/lang/String;)V")); - insns.add(new VarInsnNode(ASTORE, threadIndex)); - } - if(!config.lwjglFrame.get()) { + insns.add(new MethodInsnNode(INVOKEINTERFACE, "java/lang/Runnable", "run", "()V")); + } else { insns.add(new VarInsnNode(ALOAD, frameIndex)); insns.add(new InsnNode(ICONST_1)); insns.add(new MethodInsnNode(INVOKEVIRTUAL, "java/awt/Frame", "setVisible", "(Z)V")); @@ -232,9 +227,6 @@ protected MethodNode getMain(ClassNodeSource source, LaunchConfig config) { insns.add(new MethodInsnNode(INVOKESPECIAL, listenerClass, "", "(L" + minecraft.name + ";)V")); insns.add(new MethodInsnNode(INVOKEVIRTUAL, "java/awt/Frame", "addWindowListener", "(Ljava/awt/event/WindowListener;)V")); createWindowListener(source, listenerClass); - } else { - insns.add(new VarInsnNode(ALOAD, threadIndex)); - insns.add(new MethodInsnNode(INVOKEVIRTUAL, "java/lang/Thread", "start", "()V")); } insns.add(new InsnNode(RETURN)); return node; @@ -422,15 +414,15 @@ private InsnList getNewMinecraftImpl(ClassNode minecraftImpl, String canvasField } else if(i == 1) { insns.add(intInsn(config.height.get())); } else { + Launch.LOGGER.logErr("Unexpected Minecraft constructor: " + init.desc); return null; - // throw new IllegalStateException("Unexpected constructor: " + init.desc); } i++; } else if(desc.equals("Z")) { insns.add(booleanInsn(config.fullscreen.get())); } else { + Launch.LOGGER.logErr("Unexpected Minecraft constructor: " + init.desc); return null; - // throw new IllegalStateException("Unexpected constructor: " + init.desc); } } insns.add(new MethodInsnNode(INVOKESPECIAL, minecraftImpl.name, "", init.desc)); 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 39b9696..916ba19 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 @@ -105,10 +105,10 @@ public boolean apply(ClassNodeSource source, LaunchConfig config) { if(compareInsn(insns1[0], ALOAD, 0) && compareInsn(insns1[1], GETFIELD, minecraft.name, running.name, running.desc) && compareInsn(insns1[2], IFEQ)) { - start = new LabelNode(); - run.instructions.insertBefore(insn1, start); - JumpInsnNode jmp = (JumpInsnNode) insns1[2]; - end = previousInsn(jmp.label); // GOTO outside of loop + start = labelBefore(insn1); + // run.instructions.insertBefore(insn1, start); + // JumpInsnNode jmp = (JumpInsnNode) insns1[2]; + // end = previousInsn(jmp.label); for(TryCatchBlockNode tryCatch : run.tryCatchBlocks) { if(afterCatch == null && tryCatch.type != null && !tryCatch.type.startsWith("java/lang/")) { afterCatch = tryCatch; @@ -140,6 +140,13 @@ && compareInsn(testInsn2, INVOKEVIRTUAL, minecraft.name, null, "()V")) { } insn1 = nextInsn(insn1); } + insn1 = run.instructions.getFirst(); + while(insn1 != null) { + if(insn1.getType() == AbstractInsnNode.JUMP_INSN && ((JumpInsnNode)insn1).label == start) { + end = insn1; + } + insn1 = nextInsn(insn1); + } if(start == null || end == null) { return false; } @@ -332,7 +339,7 @@ && compareInsn(insns2[1], DUP)) { } if(setWorld == null && cleanup == null) { return false; - } + } int n = getFreeIndex(run.instructions); InsnList handle = new InsnList(); 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 7ff8932..04a0fcb 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 @@ -145,7 +145,8 @@ && compareInsn(insn, INVOKESPECIAL, minecraft.name, null, "()V")) { return run; } - private InsnList getIcon(boolean grassIcon) { + private InsnList getIcon() { + boolean grassIcon = context.isClassic(); InsnList insert = new InsnList(); insert.add(booleanInsn(grassIcon)); insert.add(new MethodInsnNode(INVOKESTATIC, "org/mcphackers/launchwrapper/util/IconUtils", "loadIcon", "(Z)[Ljava/nio/ByteBuffer;")); @@ -210,7 +211,7 @@ && compareInsn(insns[2], SIPUSH) && compareInsn(insns[3], SIPUSH) && compareInsn(insns[4], INVOKESPECIAL, "org/lwjgl/opengl/DisplayMode", "", "(II)V") && compareInsn(insns[5], INVOKESTATIC, "org/lwjgl/opengl/Display", "setDisplayMode", "(Lorg/lwjgl/opengl/DisplayMode;)V")) { - InsnList insert = getIcon(context.isClassic()); + InsnList insert = getIcon(); if(config.forceVsync.get()) { insert.add(new InsnNode(ICONST_1)); insert.add(new MethodInsnNode(INVOKESTATIC, "org/lwjgl/opengl/Display", "setVSyncEnabled", "(Z)V")); @@ -231,7 +232,7 @@ && compareInsn(insns[4], INVOKESPECIAL, "org/lwjgl/opengl/DisplayMode", "" if(compareInsn(insns[0], ICONST_1) && compareInsn(insns[1], INVOKESTATIC, "org/lwjgl/opengl/Display", "setFullscreen", "(Z)V") && compareInsn(insns[2], INVOKESTATIC, "org/lwjgl/opengl/Display", "create", "()V")) { - InsnList insert = getIcon(context.isClassic()); + InsnList insert = getIcon(); if(config.forceVsync.get()) { insert.add(new InsnNode(ICONST_1)); insert.add(new MethodInsnNode(INVOKESTATIC, "org/lwjgl/opengl/Display", "setVSyncEnabled", "(Z)V")); @@ -288,8 +289,7 @@ && compareInsn(insns[1], INVOKESTATIC, "org/lwjgl/opengl/Display", "setFullscree && ifNoCanvas != null && ifFullscreen != null) { insnList.insertBefore(afterLabel, aLabel); - InsnList insert = new InsnList(); - insert.add(getIcon(context.isClassic())); + InsnList insert = getIcon(); if(supportsResizing) { insert.add(new InsnNode(ICONST_1)); insert.add(new MethodInsnNode(INVOKESTATIC, "org/lwjgl/opengl/Display", "setResizable", "(Z)V")); diff --git a/src/main/java/org/mcphackers/launchwrapper/util/IconUtils.java b/src/main/java/org/mcphackers/launchwrapper/util/IconUtils.java index aade8a4..af55cf3 100644 --- a/src/main/java/org/mcphackers/launchwrapper/util/IconUtils.java +++ b/src/main/java/org/mcphackers/launchwrapper/util/IconUtils.java @@ -44,7 +44,9 @@ public static ByteBuffer[] loadIcon(boolean favIcon) { if(!favIcon) { return new ByteBuffer[] { loadIcon("/icon_16x16.png"), - loadIcon("/icon_32x32.png") }; + loadIcon("/icon_32x32.png"), + loadIcon("/icon_48x48.png"), + loadIcon("/icon_256x256.png") }; } else { return new ByteBuffer[] { @@ -94,7 +96,7 @@ public static BufferedImage getIcon(boolean favIcon) { } try { if(!favIcon) { - return getIcon("/icon_32x32.png"); + return getIcon("/icon_256x256.png"); } else { return getIcon("/favicon.png"); }