From c0c67b233934c30a6bf5e51256b3541fd4b83840 Mon Sep 17 00:00:00 2001
From: Cody <149296239+notdevcody@users.noreply.github.com>
Date: Fri, 14 Jun 2024 20:22:23 +0200
Subject: [PATCH] Minor refactoring + Beta Forge patch
---
README.md | 16 ++---
.../java/uk/betacraft/legacyfix/LFLogger.java | 22 +++---
.../betacraft/legacyfix/LegacyFixAgent.java | 32 +++++----
.../uk/betacraft/legacyfix/patch/Patch.java | 3 +-
.../legacyfix/patch/URLClassLoaderBridge.java | 2 +-
.../legacyfix/patch/impl/BetaForgePatch.java | 36 ++++++++++
.../patch/impl/DisableControllersPatch.java | 21 +++---
.../legacyfix/patch/impl/ModloaderPatch.java | 70 ++++++++-----------
.../patch/impl/TexturePackFolderPatch.java | 51 ++++++++++++++
.../patch/impl/TexturepackFolderPatch.java | 59 ----------------
10 files changed, 166 insertions(+), 146 deletions(-)
create mode 100644 src/main/java/uk/betacraft/legacyfix/patch/impl/BetaForgePatch.java
create mode 100644 src/main/java/uk/betacraft/legacyfix/patch/impl/TexturePackFolderPatch.java
delete mode 100644 src/main/java/uk/betacraft/legacyfix/patch/impl/TexturepackFolderPatch.java
diff --git a/README.md b/README.md
index beff577..ccdc5f8 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,9 @@
-# LegacyFix
-![](/.github/img/banner.webp)
+
+
LegacyFix
+A utility made to patch old and misbehaving versions of Minecraft.
+
-## What is it?
-LegacyFix is a utility made to patch old and misbehaving versions of Minecraft.
+![](/.github/img/banner.webp)
### What does it patch?
It aims to patch all known issues with running legacy Minecraft.
@@ -22,9 +23,8 @@ As of now:
- [ ] Joining servers with c0.0.15a
- [ ] Unnecessary duplicates of sound files and assets
- [ ] Offline saving in Classic versions
+- [x] Forge for b1.7.3 - b1.8.1
### How can I use it?
-TODO
-
-### What programs use it?
-- [BetaCraft Launcher V2](https://github.com/betacraftuk/betacraft-launcher/tree/v2)
+- Used by default in the [BetaCraft v2 Launcher](https://github.com/betacraftuk/betacraft-launcher/tree/v2)
+- Apply the javaagent in the launcher of your choice
\ No newline at end of file
diff --git a/src/main/java/uk/betacraft/legacyfix/LFLogger.java b/src/main/java/uk/betacraft/legacyfix/LFLogger.java
index 0ea0666..7e39cb1 100644
--- a/src/main/java/uk/betacraft/legacyfix/LFLogger.java
+++ b/src/main/java/uk/betacraft/legacyfix/LFLogger.java
@@ -1,24 +1,24 @@
package uk.betacraft.legacyfix;
+import uk.betacraft.legacyfix.patch.Patch;
+
public class LFLogger {
- public static void info(String msg) {
- System.out.println("[INFO] LF: " + msg);
+ public static void info(String ...lines) {
+ log("INFO", lines);
}
- public static void info(String ...lines) {
- for (int i = 0; i < lines.length; i++) {
- if (i == 0) {
- System.out.println("[INFO] LF: " + lines[i]);
- } else {
- System.out.println(" " + lines[i]);
- }
- }
+ public static void error(Patch patch, Exception e) {
+ error(patch.getName(), e.toString());
}
public static void error(String ...lines) {
+ log("ERROR", lines);
+ }
+
+ public static void log(String prefix, String ...lines) {
for (int i = 0; i < lines.length; i++) {
if (i == 0) {
- System.out.println("[ERROR] LF: " + lines[i]);
+ System.out.println("[LF] " + prefix + ": " + lines[i]);
} else {
System.out.println(" " + lines[i]);
}
diff --git a/src/main/java/uk/betacraft/legacyfix/LegacyFixAgent.java b/src/main/java/uk/betacraft/legacyfix/LegacyFixAgent.java
index 2ac1c80..fb865b0 100644
--- a/src/main/java/uk/betacraft/legacyfix/LegacyFixAgent.java
+++ b/src/main/java/uk/betacraft/legacyfix/LegacyFixAgent.java
@@ -8,10 +8,7 @@
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.instrument.Instrumentation;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
public class LegacyFixAgent {
private static final Map SETTINGS = new HashMap();
@@ -19,8 +16,8 @@ public class LegacyFixAgent {
private static int jvmVersion = -1;
public static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
- private static final HashMap RELEASE_INFO = GSON.fromJson(new BufferedReader(new InputStreamReader(LegacyFixAgent.class.getResourceAsStream("/releaseInfo.json"))), HashMap.class);
- public static final String VERSION = RELEASE_INFO.containsKey("version") ? RELEASE_INFO.get("version") : "unknown";
+ private static final HashMap, ?> RELEASE_INFO = GSON.fromJson(new BufferedReader(new InputStreamReader(LegacyFixAgent.class.getResourceAsStream("/releaseInfo.json"))), HashMap.class);
+ public static final String VERSION = RELEASE_INFO.containsKey("version") ? (String) RELEASE_INFO.get("version") : "unknown";
public static void premain(String agentArgs, final Instrumentation inst) {
jvmVersion = getMajorJvmVersion();
@@ -34,17 +31,24 @@ public static void premain(String agentArgs, final Instrumentation inst) {
}
}
- PATCHES.add(new DisableControllersPatch());
- PATCHES.add(new ModloaderPatch());
- PATCHES.add(new DeAwtPatch());
- PATCHES.add(new TexturepackFolderPatch());
+ PATCHES.addAll(Arrays.asList(
+ new DisableControllersPatch(),
+ new TexturePackFolderPatch(),
+ new ModloaderPatch(),
+ new BetaForgePatch(),
+ new DeAwtPatch()
+ ));
for (Patch patch : PATCHES) {
if (patch.shouldApply()) {
- if (patch.apply(inst)) {
- LFLogger.info("Applied " + patch.getName());
- } else {
- LFLogger.error("Failed to apply " + patch.getName() + "!");
+ try {
+ if (patch.apply(inst)) {
+ LFLogger.info("Applied " + patch.getName());
+ } else {
+ LFLogger.error("Failed to apply " + patch.getName());
+ }
+ } catch (Exception e) {
+ LFLogger.error(patch, e);
}
}
}
diff --git a/src/main/java/uk/betacraft/legacyfix/patch/Patch.java b/src/main/java/uk/betacraft/legacyfix/patch/Patch.java
index c3d5cd3..75cbd5a 100644
--- a/src/main/java/uk/betacraft/legacyfix/patch/Patch.java
+++ b/src/main/java/uk/betacraft/legacyfix/patch/Patch.java
@@ -35,8 +35,9 @@ public boolean shouldApply() {
/**
* Applies the patch. Should only ever be called in the agent's premain.
* @return If the patch was correctly applied
+ * @throws Exception Exceptions related to class patching
*/
- public boolean apply(final Instrumentation inst) {
+ public boolean apply(final Instrumentation inst) throws Exception {
return true;
}
}
diff --git a/src/main/java/uk/betacraft/legacyfix/patch/URLClassLoaderBridge.java b/src/main/java/uk/betacraft/legacyfix/patch/URLClassLoaderBridge.java
index f5c7d5b..659c313 100644
--- a/src/main/java/uk/betacraft/legacyfix/patch/URLClassLoaderBridge.java
+++ b/src/main/java/uk/betacraft/legacyfix/patch/URLClassLoaderBridge.java
@@ -14,7 +14,7 @@
*/
@SuppressWarnings("unused")
public class URLClassLoaderBridge extends URLClassLoader {
- private static ArrayList urls = new ArrayList();
+ private static final ArrayList urls = new ArrayList();
static {
String classpath = System.getProperty("java.class.path");
diff --git a/src/main/java/uk/betacraft/legacyfix/patch/impl/BetaForgePatch.java b/src/main/java/uk/betacraft/legacyfix/patch/impl/BetaForgePatch.java
new file mode 100644
index 0000000..1b9ff81
--- /dev/null
+++ b/src/main/java/uk/betacraft/legacyfix/patch/impl/BetaForgePatch.java
@@ -0,0 +1,36 @@
+package uk.betacraft.legacyfix.patch.impl;
+
+import javassist.CannotCompileException;
+import javassist.CtClass;
+import javassist.expr.ExprEditor;
+import javassist.expr.MethodCall;
+import uk.betacraft.legacyfix.patch.Patch;
+
+import java.lang.instrument.ClassDefinition;
+import java.lang.instrument.Instrumentation;
+
+/**
+ * Patches b1.7.3 - b1.8.1 Forge
+ */
+public class BetaForgePatch extends Patch {
+ public BetaForgePatch() {
+ super("betaforge", "Beta Forge");
+ }
+
+ @Override
+ public boolean apply(Instrumentation inst) throws Exception {
+ CtClass clazz = pool.getOrNull("forge.ForgeHooksClient");
+ if (clazz == null) return false;
+
+ clazz.instrument(new ExprEditor() {
+ public void edit(MethodCall m) throws CannotCompileException {
+ if (m.getMethodName().equals("toArray") && m.getSignature().equals("()[Ljava/lang/Object;")) {
+ m.replace("$_ = $0.toArray(new Integer[0]);");
+ }
+ }
+ });
+
+ inst.redefineClasses(new ClassDefinition(Class.forName(clazz.getName()), clazz.toBytecode()));
+ return true;
+ }
+}
diff --git a/src/main/java/uk/betacraft/legacyfix/patch/impl/DisableControllersPatch.java b/src/main/java/uk/betacraft/legacyfix/patch/impl/DisableControllersPatch.java
index 48323f2..10ac535 100644
--- a/src/main/java/uk/betacraft/legacyfix/patch/impl/DisableControllersPatch.java
+++ b/src/main/java/uk/betacraft/legacyfix/patch/impl/DisableControllersPatch.java
@@ -13,19 +13,14 @@ public DisableControllersPatch() {
}
@Override
- public boolean apply(Instrumentation inst) {
- try {
- CtClass clazz = pool.get("org.lwjgl.input.Controllers");
- CtMethod method = clazz.getDeclaredMethod("create");
- method.setBody(
- "{ return; }"
- );
+ public boolean apply(Instrumentation inst) throws Exception {
+ CtClass clazz = pool.get("org.lwjgl.input.Controllers");
+ CtMethod method = clazz.getDeclaredMethod("create");
+ method.setBody(
+ "{ return; }"
+ );
- inst.redefineClasses(new ClassDefinition(Class.forName(clazz.getName()), clazz.toBytecode()));
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
+ inst.redefineClasses(new ClassDefinition(Class.forName(clazz.getName()), clazz.toBytecode()));
+ return true;
}
}
diff --git a/src/main/java/uk/betacraft/legacyfix/patch/impl/ModloaderPatch.java b/src/main/java/uk/betacraft/legacyfix/patch/impl/ModloaderPatch.java
index 0554c56..30b137f 100644
--- a/src/main/java/uk/betacraft/legacyfix/patch/impl/ModloaderPatch.java
+++ b/src/main/java/uk/betacraft/legacyfix/patch/impl/ModloaderPatch.java
@@ -19,7 +19,7 @@ public ModloaderPatch() {
}
@Override
- public boolean apply(Instrumentation inst) {
+ public boolean apply(Instrumentation inst) throws Exception {
if (LegacyFixAgent.getJvmVersion() >= 11) {
String args = JvmUtils.getJvmArguments();
if (!(
@@ -48,49 +48,41 @@ public boolean apply(Instrumentation inst) {
}
}
- try {
- CtClass clazz;
- CtMethod method;
- CtClass string = pool.get("java.lang.String");
+ CtClass clazz = pool.get("java.lang.Class");
+ CtClass string = pool.get("java.lang.String");
+ CtMethod method = clazz.getDeclaredMethod("getDeclaredField", new CtClass[] {string});
- clazz = pool.get("java.lang.Class");
- method = clazz.getDeclaredMethod("getDeclaredField", new CtClass[] {string});
- method.setBody(
- "{" +
- " java.lang.reflect.Field[] fieldz = getDeclaredFields0(false);" +
- " for (int i = 0; i < fieldz.length; i++) {" +
- " java.lang.reflect.Field one = fieldz[i];" +
- " if ($1.equals(one.getName())) {" +
- " return one;" +
- " }" +
- " }" +
- " return null;" +
- "}"
- );
+ method.setBody(
+ "{" +
+ " java.lang.reflect.Field[] fieldz = getDeclaredFields0(false);" +
+ " for (int i = 0; i < fieldz.length; i++) {" +
+ " java.lang.reflect.Field one = fieldz[i];" +
+ " if ($1.equals(one.getName())) {" +
+ " return one;" +
+ " }" +
+ " }" +
+ " return null;" +
+ "}"
+ );
- method = clazz.getDeclaredMethod("getDeclaredFields");
- method.setBody(
- "{" +
- " return copyFields($0.getDeclaredFields0(false));" +
- "}"
- );
+ method = clazz.getDeclaredMethod("getDeclaredFields");
+ method.setBody(
+ "{" +
+ " return copyFields($0.getDeclaredFields0(false));" +
+ "}"
+ );
- inst.redefineClasses(new ClassDefinition(Class.forName(clazz.getName()), clazz.toBytecode()));
+ inst.redefineClasses(new ClassDefinition(Class.forName(clazz.getName()), clazz.toBytecode()));
- clazz = pool.get("java.lang.ClassLoader");
- method = clazz.getDeclaredMethod("loadClass", new CtClass[] {string});
- method.insertBefore(
- "if ($1.startsWith(\"\\.mod_\")) {" +
- " $1 = $1.substring(1);" +
- "}"
- );
-
- inst.redefineClasses(new ClassDefinition(Class.forName(clazz.getName()), clazz.toBytecode()));
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
+ clazz = pool.get("java.lang.ClassLoader");
+ method = clazz.getDeclaredMethod("loadClass", new CtClass[] {string});
+ method.insertBefore(
+ "if ($1.startsWith(\"\\.mod_\")) {" +
+ " $1 = $1.substring(1);" +
+ "}"
+ );
+ inst.redefineClasses(new ClassDefinition(Class.forName(clazz.getName()), clazz.toBytecode()));
return true;
}
diff --git a/src/main/java/uk/betacraft/legacyfix/patch/impl/TexturePackFolderPatch.java b/src/main/java/uk/betacraft/legacyfix/patch/impl/TexturePackFolderPatch.java
new file mode 100644
index 0000000..45b6911
--- /dev/null
+++ b/src/main/java/uk/betacraft/legacyfix/patch/impl/TexturePackFolderPatch.java
@@ -0,0 +1,51 @@
+package uk.betacraft.legacyfix.patch.impl;
+
+import java.lang.instrument.ClassDefinition;
+import java.lang.instrument.Instrumentation;
+
+import javassist.CtClass;
+import javassist.CtMethod;
+import uk.betacraft.legacyfix.LFLogger;
+import uk.betacraft.legacyfix.patch.Patch;
+
+/**
+ * Patch for unresponsive "Open texture pack folder" button in versions before 1.2-pre on Linux and macOS
+ */
+public class TexturePackFolderPatch extends Patch {
+ public TexturePackFolderPatch() {
+ super("texturePackButton", "Patch open texture pack folder button");
+ }
+
+ @Override
+ public boolean apply(final Instrumentation inst) throws Exception {
+ CtClass clazz;
+ CtMethod method;
+ CtClass string = pool.get("java.lang.String");
+
+ clazz = pool.getOrNull("org.lwjgl.Sys");
+ if (clazz == null) return false;
+
+ method = clazz.getDeclaredMethod("openURL", new CtClass[] {string});
+ method.insertBefore(
+ "if ($1 != null && $1.indexOf(\"file://\") == 0) {" +
+ " String txpfolder = $1.substring(7);" +
+ " try {" +
+ " Class desktopClass = Class.forName(\"java.awt.Desktop\");" +
+ " Object desktop = desktopClass.getMethod(\"getDesktop\").invoke((Object) null);" +
+ " desktopClass.getMethod(\"browse\", java.net.URI.class).invoke(desktop, (new java.io.File(txpfolder)).toURI());" +
+ " return true;" +
+ " } catch (Throwable t) {" +
+ " t.printStackTrace();" + // if failed, don't return and have a shot at the Sys.openURL method (vanilla behavior since 1.2-pre)
+ " }" +
+ "}"
+ );
+
+ inst.redefineClasses(new ClassDefinition(Class.forName(clazz.getName()), clazz.toBytecode()));
+ return true;
+ }
+
+ @Override
+ public boolean shouldApply() {
+ return true;
+ }
+}
diff --git a/src/main/java/uk/betacraft/legacyfix/patch/impl/TexturepackFolderPatch.java b/src/main/java/uk/betacraft/legacyfix/patch/impl/TexturepackFolderPatch.java
deleted file mode 100644
index 164be6e..0000000
--- a/src/main/java/uk/betacraft/legacyfix/patch/impl/TexturepackFolderPatch.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package uk.betacraft.legacyfix.patch.impl;
-
-import java.lang.instrument.ClassDefinition;
-import java.lang.instrument.Instrumentation;
-
-import javassist.CtClass;
-import javassist.CtMethod;
-import uk.betacraft.legacyfix.patch.Patch;
-
-/**
- * Patch for unresponsive "Open texture pack folder" button in versions before 1.2-pre on Linux and macOS
- */
-public class TexturepackFolderPatch extends Patch {
-
- public TexturepackFolderPatch() {
- super("patchTexturepackButton", "Patch open texture pack folder button");
- }
-
- @Override
- public boolean apply(final Instrumentation inst) {
- try {
- CtClass clazz;
- CtMethod method;
- CtClass string = pool.get("java.lang.String");
-
- clazz = pool.getOrNull("org.lwjgl.Sys");
-
- if (clazz == null)
- return true;
-
- method = clazz.getDeclaredMethod("openURL", new CtClass[] {string});
- method.insertBefore(
- "if ($1 != null && $1.indexOf(\"file://\") == 0) {" +
- " String txpfolder = $1.substring(7);" +
- " try {" +
- " Class desktopClass = Class.forName(\"java.awt.Desktop\");" +
- " Object desktop = desktopClass.getMethod(\"getDesktop\").invoke((Object) null);" +
- " desktopClass.getMethod(\"browse\", java.net.URI.class).invoke(desktop, (new java.io.File(txpfolder)).toURI());" +
- " return true;" + // stop and return if successful
- " } catch (Throwable t) {" +
- " t.printStackTrace();" + // if failed, don't return and have a shot at the Sys.openURL method (vanilla behavior since 1.2-pre)
- " }" +
- "}"
- );
-
- inst.redefineClasses(new ClassDefinition(Class.forName(clazz.getName()), clazz.toBytecode()));
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
-
- return true;
- }
-
- @Override
- public boolean shouldApply() {
- return true;
- }
-}