diff --git a/src/main/java/net/minecraft/launchwrapper/Launch.java b/src/main/java/net/minecraft/launchwrapper/Launch.java index 6f6b5f1..da4178b 100644 --- a/src/main/java/net/minecraft/launchwrapper/Launch.java +++ b/src/main/java/net/minecraft/launchwrapper/Launch.java @@ -14,6 +14,7 @@ import org.mcphackers.launchwrapper.target.LaunchTarget; import org.mcphackers.launchwrapper.target.MainLaunchTarget; import org.mcphackers.launchwrapper.tweak.Tweak; +import org.mcphackers.launchwrapper.tweak.injection.forge.ForgeFix; public final class Launch extends org.mcphackers.launchwrapper.Launch { public static File minecraftHome; @@ -55,8 +56,9 @@ public void launch() { blackboard.put("ArgumentList", new ArrayList()); minecraftHome = config.gameDir.get(); assetsDir = config.assetsDir.get(); - runTweakers(); LaunchClassLoader loader = getLoader(); + runPreInitTweaks(loader); + runTweakers(loader); Tweak mainTweak = getTweak(); if (mainTweak == null) { if (config.tweakClass.get() == null) { @@ -103,9 +105,12 @@ private List getArgs() { return args; } + private void runPreInitTweaks(LaunchClassLoader loader) { + new ForgeFix().apply(loader, config); + } + @SuppressWarnings("unchecked") - private void runTweakers() { - LaunchClassLoader loader = getLoader(); + private void runTweakers(LaunchClassLoader loader) { List args = getArgs(); List tweakClassNames = (List)blackboard.get("TweakClasses"); diff --git a/src/main/java/org/mcphackers/launchwrapper/loader/LaunchClassLoader.java b/src/main/java/org/mcphackers/launchwrapper/loader/LaunchClassLoader.java index 4c7b8df..3da95bc 100644 --- a/src/main/java/org/mcphackers/launchwrapper/loader/LaunchClassLoader.java +++ b/src/main/java/org/mcphackers/launchwrapper/loader/LaunchClassLoader.java @@ -203,6 +203,8 @@ public void invokeMain(String launchTarget, String... args) { } catch (InvocationTargetException e1) { if (e1.getCause() != null) { e1.getCause().printStackTrace(); + } else { + e1.printStackTrace(); } } catch (Exception e) { e.printStackTrace(); diff --git a/src/main/java/org/mcphackers/launchwrapper/protocol/SaveRequests.java b/src/main/java/org/mcphackers/launchwrapper/protocol/SaveRequests.java index 8c69db9..4b677fd 100644 --- a/src/main/java/org/mcphackers/launchwrapper/protocol/SaveRequests.java +++ b/src/main/java/org/mcphackers/launchwrapper/protocol/SaveRequests.java @@ -71,18 +71,26 @@ public static byte[] loadLevel(File levelsDir, int index) throws IOException { * Used in level save screen */ public static void saveLevel(File levelsDir, int index, String levelName, byte[] data) throws IOException { + if (!levelsDir.exists()) { + levelsDir.mkdirs(); + } + if (!levelsDir.isDirectory()) { + throw new IOException(levelsDir + " is not a directory"); + } String[] lvlNames = getLevelNames(levelsDir); lvlNames[index] = levelName; File level = new File(levelsDir, "level" + index + ".dat"); + if (!levelsDir.exists()) { + levelsDir.mkdirs(); + } // Since minecraft doesn't have a delete button on levels, just save a new one with this name and it'll get deleted if (levelName.equals("---") /* Can't be "-" because save button is active at 3>= characters */) { - level.delete(); + if (level.exists()) { + level.delete(); + } lvlNames[index] = EMPTY_LEVEL; } else { - if (!levelsDir.exists()) { - levelsDir.mkdirs(); - } OutputStream fileOutput = new FileOutputStream(level); try { fileOutput.write(data); diff --git a/src/main/java/org/mcphackers/launchwrapper/tweak/Java5LazyTweaker.java b/src/main/java/org/mcphackers/launchwrapper/tweak/Java5Tweaker.java similarity index 98% rename from src/main/java/org/mcphackers/launchwrapper/tweak/Java5LazyTweaker.java rename to src/main/java/org/mcphackers/launchwrapper/tweak/Java5Tweaker.java index 18141f0..e9f3956 100644 --- a/src/main/java/org/mcphackers/launchwrapper/tweak/Java5LazyTweaker.java +++ b/src/main/java/org/mcphackers/launchwrapper/tweak/Java5Tweaker.java @@ -17,7 +17,7 @@ * Compatibility fixes for Java 5. * Replaces most of Java 6 API used by Minecraft with Java 5 alternative */ -public class Java5LazyTweaker implements Tweaker { +public class Java5Tweaker implements Tweaker { public boolean tweakClass(ClassNodeSource source, String name) { ClassNode node = source.getClass(name); diff --git a/src/main/java/org/mcphackers/launchwrapper/tweak/LegacyLauncherTweak.java b/src/main/java/org/mcphackers/launchwrapper/tweak/LegacyLauncherTweak.java new file mode 100644 index 0000000..711171c --- /dev/null +++ b/src/main/java/org/mcphackers/launchwrapper/tweak/LegacyLauncherTweak.java @@ -0,0 +1,37 @@ +package org.mcphackers.launchwrapper.tweak; + +import java.util.ArrayList; +import java.util.List; + +import org.mcphackers.launchwrapper.LaunchConfig; +import org.mcphackers.launchwrapper.target.LaunchTarget; +import org.mcphackers.launchwrapper.tweak.injection.Injection; +import org.mcphackers.launchwrapper.tweak.injection.forge.ForgeFix; + +public class LegacyLauncherTweak extends Tweak { + + protected Tweak baseTweak; + + public LegacyLauncherTweak(LaunchConfig config, Tweak tweak) { + super(config); + baseTweak = tweak; + } + + @Override + public List getInjections() { + List injections = new ArrayList(); + injections.addAll(baseTweak.getInjections()); + injections.add(new ForgeFix()); + return injections; + } + + @Override + public List getTweakers() { + return baseTweak.getTweakers(); + } + + @Override + public LaunchTarget getLaunchTarget() { + return baseTweak.getLaunchTarget(); + } +} diff --git a/src/main/java/org/mcphackers/launchwrapper/tweak/LegacyTweak.java b/src/main/java/org/mcphackers/launchwrapper/tweak/LegacyTweak.java index 310e786..ffe6162 100644 --- a/src/main/java/org/mcphackers/launchwrapper/tweak/LegacyTweak.java +++ b/src/main/java/org/mcphackers/launchwrapper/tweak/LegacyTweak.java @@ -89,7 +89,7 @@ public List getInjections() { @Override public List getTweakers() { - return Collections.singletonList(new Java5LazyTweaker()); + return Collections.singletonList(new Java5Tweaker()); } @Override diff --git a/src/main/java/org/mcphackers/launchwrapper/tweak/VanillaTweak.java b/src/main/java/org/mcphackers/launchwrapper/tweak/VanillaTweak.java index 3fb0e20..735dfaa 100644 --- a/src/main/java/org/mcphackers/launchwrapper/tweak/VanillaTweak.java +++ b/src/main/java/org/mcphackers/launchwrapper/tweak/VanillaTweak.java @@ -39,7 +39,7 @@ public List getInjections() { @Override public List getTweakers() { - return Collections.singletonList(new Java5LazyTweaker()); + return Collections.singletonList(new Java5Tweaker()); } @Override diff --git a/src/main/java/org/mcphackers/launchwrapper/tweak/injection/forge/ForgeClassLoader.java b/src/main/java/org/mcphackers/launchwrapper/tweak/injection/forge/ForgeClassLoader.java deleted file mode 100644 index f020882..0000000 --- a/src/main/java/org/mcphackers/launchwrapper/tweak/injection/forge/ForgeClassLoader.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.mcphackers.launchwrapper.tweak.injection.forge; - -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.launchwrapper.util.asm.NodeHelper; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.FieldInsnNode; -import org.objectweb.asm.tree.InsnList; -import org.objectweb.asm.tree.MethodNode; -import org.objectweb.asm.tree.VarInsnNode; - -public class ForgeClassLoader implements Injection { - - public String name() { - return "Forge ClassLoader patch"; - } - - public boolean required() { - return false; - } - - public boolean apply(ClassNodeSource source, LaunchConfig config) { - ClassNode modClassLoader = source.getClass("net/minecraftforge/fml/common/ModClassLoader"); - if (modClassLoader == null) { - return false; - } - MethodNode init = NodeHelper.getMethod(modClassLoader, "", "(Ljava/lang/ClassLoader;)V"); - if (init == null) { - return false; - } - InsnList inject = new InsnList(); - inject.add(new FieldInsnNode(GETSTATIC, "net/minecraft/launchwrapper/Launch", "classLoader", "Lnet/minecraft/launchwrapper/LaunchClassLoader;")); - inject.add(new VarInsnNode(ASTORE, 1)); - init.instructions.insert(inject); - source.overrideClass(modClassLoader); - return true; - } -} diff --git a/src/main/java/org/mcphackers/launchwrapper/tweak/injection/forge/ForgeFix.java b/src/main/java/org/mcphackers/launchwrapper/tweak/injection/forge/ForgeFix.java new file mode 100644 index 0000000..65a17cb --- /dev/null +++ b/src/main/java/org/mcphackers/launchwrapper/tweak/injection/forge/ForgeFix.java @@ -0,0 +1,45 @@ +package org.mcphackers.launchwrapper.tweak.injection.forge; + +import static org.mcphackers.launchwrapper.util.asm.InsnHelper.*; +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.launchwrapper.util.asm.NodeHelper; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; + +public class ForgeFix implements Injection { + + public String name() { + return "Forge patch"; + } + + public boolean required() { + return false; + } + + public boolean apply(ClassNodeSource source, LaunchConfig config) { + ClassNode eventSubscriptionTransformer = source.getClass("net/minecraftforge/fml/common/asm/transformers/EventSubscriptionTransformer"); + if (eventSubscriptionTransformer == null) { + return false; + } + MethodNode buildEvents = NodeHelper.getMethod(eventSubscriptionTransformer, "buildEvents", "(Lorg/objectweb/asm/tree/ClassNode;)Z"); + if (buildEvents == null) { + return false; + } + for (AbstractInsnNode insn = getFirst(buildEvents.instructions); insn != null; insn = nextInsn(insn)) { + if (compareInsn(insn, GETFIELD, "org/objectweb/asm/tree/ClassNode", "superName", "Ljava/lang/String;") && + compareInsn(nextInsn(insn), INVOKESTATIC, "org/objectweb/asm/Type", "getType", "(Ljava/lang/String;)Lorg/objectweb/asm/Type;")) { + // Forge incorrectly uses getType here. getObjectType makes it compatible with asm 9.7+ + buildEvents.instructions.set(nextInsn(insn), new MethodInsnNode(INVOKESTATIC, "org/objectweb/asm/Type", "getObjectType", "(Ljava/lang/String;)Lorg/objectweb/asm/Type;")); + break; + } + } + source.overrideClass(eventSubscriptionTransformer); + return true; + } +} diff --git a/src/test/java/org/mcphackers/launchwrapper/test/IndevTest.java b/src/test/java/org/mcphackers/launchwrapper/test/IndevTest.java index 3bcd577..67150af 100644 --- a/src/test/java/org/mcphackers/launchwrapper/test/IndevTest.java +++ b/src/test/java/org/mcphackers/launchwrapper/test/IndevTest.java @@ -24,6 +24,6 @@ public Tweak getTweak(LaunchConfig config) { @Override public TestFeatureBuilder getTests() { return new TestFeatureBuilder() - .tweakInfoList("LegacyTweak init", "Fix Shutdown", "Indev save patch", "LWJGL Patch", "Replace game directory", "Options load fix", "Add main"); + .tweakInfoList("LegacyTweak init", "Classic crash screen", "Fix Shutdown", "Indev save patch", "LWJGL Patch", "Replace game directory", "Options load fix", "Add main"); } }