diff options
author | Alkalus <3060479+draknyte1@users.noreply.github.com> | 2020-01-19 14:56:21 +0000 |
---|---|---|
committer | Alkalus <3060479+draknyte1@users.noreply.github.com> | 2020-01-19 14:56:21 +0000 |
commit | 34646419362b3b2a5a26d77310dada90bce8fa77 (patch) | |
tree | 348c64e81958d9e356cca932a529472b77c2ac62 | |
parent | 7584c062ba3bffa32ced43d86aec839cf3c435bd (diff) | |
download | GT5-Unofficial-34646419362b3b2a5a26d77310dada90bce8fa77.tar.gz GT5-Unofficial-34646419362b3b2a5a26d77310dada90bce8fa77.tar.bz2 GT5-Unofficial-34646419362b3b2a5a26d77310dada90bce8fa77.zip |
$ Fixed inner class lookup in ReflectionUtils.
$ Can't patch LWJGL's Keyboard class, so now I patch ClientSettings.
4 files changed, 287 insertions, 69 deletions
diff --git a/src/Java/gtPlusPlus/core/util/reflect/ReflectionUtils.java b/src/Java/gtPlusPlus/core/util/reflect/ReflectionUtils.java index 135f98dd17..4d8a02d800 100644 --- a/src/Java/gtPlusPlus/core/util/reflect/ReflectionUtils.java +++ b/src/Java/gtPlusPlus/core/util/reflect/ReflectionUtils.java @@ -43,7 +43,7 @@ public class ReflectionUtils { } } - + private static class CachedMethod { private final boolean STATIC; @@ -134,7 +134,7 @@ public class ReflectionUtils { return false; } - + /** * Returns a cached {@link Constructor} object. * @param aClass - Class containing the Constructor. @@ -145,7 +145,7 @@ public class ReflectionUtils { if (aClass == null || aTypes == null) { return null; } - + String aMethodKey = ArrayUtils.toString(aTypes); //Logger.REFLECTION("Looking up method in cache: "+(aClass.getName()+"."+aMethodName + "." + aMethodKey)); CachedConstructor y = mCachedConstructors.get(aClass.getName() + "." + aMethodKey); @@ -162,9 +162,9 @@ public class ReflectionUtils { return y.get(); } } - - - + + + /** * Returns a cached {@link Class} object. @@ -227,14 +227,14 @@ public class ReflectionUtils { return y.get(); } } - + public static boolean isStaticMethod(Class<?> aClass, String aMethodName, Class<?>... aTypes) { return isStaticMethod(ReflectionUtils.getMethod(aClass, aMethodName, aTypes)); } - + public static boolean isStaticMethod(Method aMethod) { if (aMethod != null && Modifier.isStatic(aMethod.getModifiers())) { - return true; + return true; } return false; } @@ -467,7 +467,7 @@ public class ReflectionUtils { Logger.REFLECTION("Invoke failed or did something wrong."); return false; } - + public static boolean invoke(Object objectInstance, Method method, Object[] values){ if (method == null || values == null || (!ReflectionUtils.isStaticMethod(method) && objectInstance == null)){ //Logger.REFLECTION("Null value when trying to Dynamically invoke "+methodName+" on an object of type: "+objectInstance.getClass().getName()); @@ -774,7 +774,7 @@ public class ReflectionUtils { } return m; } - + private static Constructor<?> getConstructor_Internal(Class<?> aClass, Class<?>... aTypes) { Constructor<?> c = null; try { @@ -801,7 +801,7 @@ public class ReflectionUtils { } return c; } - + private static Constructor<?> getConstructorRecursively(Class<?> aClass, Class<?>... aTypes) throws Exception { try { Logger.REFLECTION("Constructor: Recursion Lookup: "+aClass.getName()); @@ -921,31 +921,40 @@ public class ReflectionUtils { aClassName += (i > 0) ? "."+aData[i] : ""+aData[i]; Logger.REFLECTION("Building: "+aClassName); } - Logger.REFLECTION("Trying to search '"+aClassName+"' for inner classes."); - Class<?> clazz = ReflectionUtils.getClass(aClassName); - - Class[] y = clazz.getDeclaredClasses(); - if (y == null || y.length <= 0) { - Logger.REFLECTION("No hidden inner classes found."); - return null; - } - else { - boolean found = false; - for (Class<?> h : y) { - Logger.REFLECTION("Found hidden inner class: "+h.getCanonicalName()); - if (h.getSimpleName().toLowerCase().equals(aData[aData.length-1].toLowerCase())) { - Logger.REFLECTION("Found correct class. ["+aData[aData.length-1]+"] Caching at correct location: "+string); - Logger.REFLECTION("Found at location: "+h.getCanonicalName()); - ReflectionUtils.mCachedClasses.put(string, h); - aClass = h; - found = true; - break; + if (aClassName != null && aClassName.length() > 0) { + Logger.REFLECTION("Trying to search '"+aClassName+"' for inner classes."); + Class<?> clazz = ReflectionUtils.getClass(aClassName); + if (clazz != null) { + Class[] y = clazz.getDeclaredClasses(); + if (y == null || y.length <= 0) { + Logger.REFLECTION("No hidden inner classes found."); + return null; + } + else { + boolean found = false; + for (Class<?> h : y) { + Logger.REFLECTION("Found hidden inner class: "+h.getCanonicalName()); + if (h.getSimpleName().toLowerCase().equals(aData[aData.length-1].toLowerCase())) { + Logger.REFLECTION("Found correct class. ["+aData[aData.length-1]+"] Caching at correct location: "+string); + Logger.REFLECTION("Found at location: "+h.getCanonicalName()); + ReflectionUtils.mCachedClasses.put(string, h); + aClass = h; + found = true; + break; + } + } + if (!found) { + return null; + } } } - if (!found) { + else { return null; } } + else { + return null; + } } return aClass; } @@ -964,11 +973,9 @@ public class ReflectionUtils { */ private static void makeModifiable(Field nameField) throws Exception { nameField.setAccessible(true); - int modifiers = nameField.getModifiers(); - Field modifierField = nameField.getClass().getDeclaredField("modifiers"); - modifiers = modifiers & ~Modifier.FINAL; - modifierField.setAccessible(true); - modifierField.setInt(nameField, modifiers); + Field modifiers = getField(Field.class, "modifiers"); + modifiers.setAccessible(true); + modifiers.setInt(nameField, nameField.getModifiers() & ~Modifier.FINAL); } diff --git a/src/Java/gtPlusPlus/preloader/asm/transformers/ClassTransformer_LWJGL_Keyboard.java b/src/Java/gtPlusPlus/preloader/asm/transformers/ClassTransformer_LWJGL_Keyboard.java index 7a92c3d18c..929b443d33 100644 --- a/src/Java/gtPlusPlus/preloader/asm/transformers/ClassTransformer_LWJGL_Keyboard.java +++ b/src/Java/gtPlusPlus/preloader/asm/transformers/ClassTransformer_LWJGL_Keyboard.java @@ -18,6 +18,7 @@ import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import cpw.mods.fml.relauncher.FMLRelaunchLog; +import gtPlusPlus.api.objects.Logger; import gtPlusPlus.core.util.reflect.ReflectionUtils; public class ClassTransformer_LWJGL_Keyboard { @@ -40,6 +41,7 @@ public class ClassTransformer_LWJGL_Keyboard { return aTemp[key]; } } + Logger.INFO("Unable to map key code "+key+" to LWJGL keymap."); return getKeyName()[0x00]; // Return nothing } @@ -77,20 +79,27 @@ public class ClassTransformer_LWJGL_Keyboard { return new String[] {}; } - public ClassTransformer_LWJGL_Keyboard(byte[] basicClass) { + public ClassTransformer_LWJGL_Keyboard(byte[] basicClass, boolean isClientSettings) { ClassReader aTempReader = null; ClassWriter aTempWriter = null; aTempReader = new ClassReader(basicClass); - aTempWriter = new ClassWriter(aTempReader, ClassWriter.COMPUTE_FRAMES); - aTempReader.accept(new AddFieldAdapter(aTempWriter), 0); - injectMethod("getKeyName", aTempWriter); + aTempWriter = new ClassWriter(aTempReader, ClassWriter.COMPUTE_FRAMES); + if (!isClientSettings) { + //gtPlusPlus.preloader.keyboard.BetterKeyboard.init(); + aTempReader.accept(new PatchLWJGL(aTempWriter), 0); + injectLWJGLPatch(aTempWriter); + } + else { + //gtPlusPlus.preloader.keyboard.BetterKeyboard.init(); + aTempReader.accept(new PatchClientSettings(aTempWriter), 0); + injectClientSettingPatch(aTempWriter); + } if (aTempReader != null && aTempWriter != null) { isValid = true; } else { isValid = false; } - FMLRelaunchLog.log("[GT++ ASM] LWJGL Keybinding index out of bounds fix", Level.INFO, - "Valid? " + isValid + "."); + FMLRelaunchLog.log("[GT++ ASM] LWJGL Keybinding index out of bounds fix", Level.INFO, "Valid? " + isValid + "."); reader = aTempReader; writer = aTempWriter; } @@ -107,37 +116,103 @@ public class ClassTransformer_LWJGL_Keyboard { return writer; } - public boolean injectMethod(String aMethodName, ClassWriter cw) { + private boolean isClientSettingsObfuscated = false; + + + public boolean injectLWJGLPatch(ClassWriter cw) { MethodVisitor mv; boolean didInject = false; FMLRelaunchLog.log("[GT++ ASM] LWJGL Keybinding index out of bounds fix", Level.INFO, - "Injecting " + aMethodName + "."); - if (aMethodName.equals("getKeyName")) { - mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC + ACC_SYNCHRONIZED, "getKeyName", "(I)Ljava/lang/String;", null, - null); - mv.visitCode(); - Label l0 = new Label(); - mv.visitLabel(l0); - mv.visitLineNumber(49, l0); - mv.visitVarInsn(ILOAD, 0); - mv.visitMethodInsn(INVOKESTATIC, "gtPlusPlus/preloader/asm/transformers/ClassTransformer_LWJGL_Keyboard", - "getKeyName", "(I)Ljava/lang/String;", false); - mv.visitInsn(ARETURN); - Label l1 = new Label(); - mv.visitLabel(l1); - mv.visitLocalVariable("key", "I", null, l0, l1, 0); - mv.visitMaxs(1, 1); - mv.visitEnd(); - didInject = true; - } - FMLRelaunchLog.log("[GT++ ASM] LWJGL Keybinding index out of bounds fix", Level.INFO, - "Method injection complete."); + "Injecting " + "getKeyName" + "."); + mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC + ACC_SYNCHRONIZED, "getKeyName", "(I)Ljava/lang/String;", null, + null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitLineNumber(49, l0); + mv.visitVarInsn(ILOAD, 0); + mv.visitMethodInsn(INVOKESTATIC, "gtPlusPlus/preloader/asm/transformers/ClassTransformer_LWJGL_Keyboard", + "getKeyName", "(I)Ljava/lang/String;", false); + mv.visitInsn(ARETURN); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitLocalVariable("key", "I", null, l0, l1, 0); + mv.visitMaxs(1, 1); + mv.visitEnd(); + didInject = true; + + FMLRelaunchLog.log("[GT++ ASM] LWJGL Keybinding index out of bounds fix", Level.INFO, "Method injection complete."); + return didInject; + } + + + public boolean injectClientSettingPatch(ClassWriter cw) { + MethodVisitor mv; + boolean didInject = false; + String aMethodName = this.isClientSettingsObfuscated ? "func_74298_c" : "getKeyDisplayString"; + FMLRelaunchLog.log("[GT++ ASM] LWJGL Keybinding index out of bounds fix", Level.INFO, "Injecting " + aMethodName + "."); + mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, aMethodName, "(I)Ljava/lang/String;", null, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitLineNumber(130, l0); + mv.visitVarInsn(ILOAD, 0); + mv.visitMethodInsn(INVOKESTATIC, "gtPlusPlus/preloader/keyboard/BetterKeyboard", "getKeyDisplayString", "(I)Ljava/lang/String;", false); + mv.visitInsn(ARETURN); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitLocalVariable("p_74298_0_", "I", null, l0, l1, 0); + mv.visitMaxs(1, 1); + mv.visitEnd(); + didInject = true; + FMLRelaunchLog.log("[GT++ ASM] LWJGL Keybinding index out of bounds fix", Level.INFO, "Method injection complete."); return didInject; } - public class AddFieldAdapter extends ClassVisitor { - public AddFieldAdapter(ClassVisitor cv) { + + public class PatchClientSettings extends ClassVisitor { + + public PatchClientSettings(ClassVisitor cv) { + super(ASM5, cv); + this.cv = cv; + } + + private final String[] aMethodsToStrip = new String[] { "func_74298_c", "getKeyDisplayString" }; + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + MethodVisitor methodVisitor; + boolean found = false; + + for (String s : aMethodsToStrip) { + if (name.equals(s)) { + if (name.equals(aMethodsToStrip[0])) { + isClientSettingsObfuscated = true; + } + else { + isClientSettingsObfuscated = false; + } + found = true; + break; + } + } + if (!found) { + methodVisitor = super.visitMethod(access, name, desc, signature, exceptions); + } else { + methodVisitor = null; + } + if (found) { + FMLRelaunchLog.log("[GT++ ASM] LWJGL Keybinding index out of bounds fix", Level.INFO, "Found method " + name + ", removing."); + } + return methodVisitor; + } + + } + + public class PatchLWJGL extends ClassVisitor { + + public PatchLWJGL(ClassVisitor cv) { super(ASM5, cv); this.cv = cv; } diff --git a/src/Java/gtPlusPlus/preloader/asm/transformers/Preloader_Transformer_Handler.java b/src/Java/gtPlusPlus/preloader/asm/transformers/Preloader_Transformer_Handler.java index d8dc71dff0..6b9dc306b4 100644 --- a/src/Java/gtPlusPlus/preloader/asm/transformers/Preloader_Transformer_Handler.java +++ b/src/Java/gtPlusPlus/preloader/asm/transformers/Preloader_Transformer_Handler.java @@ -84,9 +84,13 @@ public class Preloader_Transformer_Handler implements IClassTransformer { boolean probablyShouldBeFalse = false; // Fix LWJGL index array out of bounds on keybinding IDs - if (transformedName.equals("org.lwjgl.input.Keyboard") && mConfig.enabledLwjglKeybindingFix) { + if ((transformedName.equals("org.lwjgl.input.Keyboard") || transformedName.equals("bbj") || transformedName.equals("net.minecraft.client.settings.GameSettings")) && mConfig.enabledLwjglKeybindingFix) { + boolean isClientSettingsClass = false; + if (!transformedName.equals("org.lwjgl.input.Keyboard")) { + isClientSettingsClass = true; + } FMLRelaunchLog.log("[GT++ ASM] LWJGL Keybinding index out of bounds fix", Level.INFO, "Transforming %s", transformedName); - return new ClassTransformer_LWJGL_Keyboard(basicClass).getWriter().toByteArray(); + return new ClassTransformer_LWJGL_Keyboard(basicClass, isClientSettingsClass).getWriter().toByteArray(); } //Enable mapping of Tickets and loaded chunks. - Forge diff --git a/src/Java/gtPlusPlus/preloader/keyboard/BetterKeyboard.java b/src/Java/gtPlusPlus/preloader/keyboard/BetterKeyboard.java new file mode 100644 index 0000000000..e25c06653c --- /dev/null +++ b/src/Java/gtPlusPlus/preloader/keyboard/BetterKeyboard.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2002-2008 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package gtPlusPlus.preloader.keyboard; + +import java.lang.reflect.Field; +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; + +import org.apache.logging.log4j.Level; +import org.lwjgl.BufferUtils; +import org.lwjgl.input.Keyboard; + +import cpw.mods.fml.relauncher.FMLRelaunchLog; +import gtPlusPlus.core.util.reflect.ReflectionUtils; +import gtPlusPlus.preloader.asm.transformers.ClassTransformer_LWJGL_Keyboard; +import net.minecraft.client.resources.I18n; + +/** + * <br> + * A raw Keyboard interface. This can be used to poll the current state of the + * keys, or read all the keyboard presses / releases since the last read. + * + * @author cix_foo <cix_foo@users.sourceforge.net> + * @author elias_naur <elias_naur@users.sourceforge.net> + * @author Brian Matzon <brian@matzon.dk> + * @version $Revision$ + * $Id$ + */ +public class BetterKeyboard { + + public static final int KEYBOARD_SIZE = Short.MAX_VALUE; + + private static boolean init = false; + + public static void init() { + if (!init) { + FMLRelaunchLog.log("[GT++ ASM] LWJGL Keybinding index out of bounds fix", Level.INFO, "Trying to patch out LWJGL internal arrays with larger ones."); + Field aKeyNameSize = ReflectionUtils.getField(Keyboard.class, "keyName"); + Field aKeyMapSize = ReflectionUtils.getField(Keyboard.class, "keyMap"); + Field aKeyDownBuffer = ReflectionUtils.getField(Keyboard.class, "keyDownBuffer"); + String[] aOldKeyNameArray = (String[]) ReflectionUtils.getFieldValue(aKeyNameSize); + if (aOldKeyNameArray != null && aOldKeyNameArray.length < Short.MAX_VALUE) { + String[] aNewKeyNameArray = new String[Short.MAX_VALUE]; + for (int i=0;i<aOldKeyNameArray.length;i++) { + aNewKeyNameArray[i] = aOldKeyNameArray[i]; + } + try { + ReflectionUtils.setFinalFieldValue(Keyboard.class, aKeyNameSize.getName(), aNewKeyNameArray); + FMLRelaunchLog.log("[GT++ ASM] LWJGL Keybinding index out of bounds fix", Level.INFO, "Patched Field: "+aKeyNameSize.getName()); + } + catch (Throwable t) { + FMLRelaunchLog.log("[GT++ ASM] LWJGL Keybinding index out of bounds fix", Level.INFO, "Failed Patching Field: "+aKeyDownBuffer.getName()); + } + } + Map<String, Integer> aOldKeyMapArray = (Map<String, Integer>) ReflectionUtils.getFieldValue(aKeyMapSize); + if (aOldKeyNameArray != null && aOldKeyMapArray.size() < Short.MAX_VALUE) { + Map<String, Integer> aNewKeyMapArray = new HashMap<String, Integer>(Short.MAX_VALUE); + aNewKeyMapArray.putAll(aOldKeyMapArray); + try { + ReflectionUtils.setFinalFieldValue(Keyboard.class, aKeyMapSize.getName(), aNewKeyMapArray); + FMLRelaunchLog.log("[GT++ ASM] LWJGL Keybinding index out of bounds fix", Level.INFO, "Patched Field: "+aKeyMapSize.getName()); + } + catch (Throwable t) { + FMLRelaunchLog.log("[GT++ ASM] LWJGL Keybinding index out of bounds fix", Level.INFO, "Failed Patching Field: "+aKeyDownBuffer.getName()); + } + } + ByteBuffer aOldByteBuffer = (ByteBuffer) ReflectionUtils.getFieldValue(aKeyDownBuffer); + if (aOldByteBuffer != null && aOldByteBuffer.capacity() == Keyboard.KEYBOARD_SIZE) { + ByteBuffer aNewByteBuffer = BufferUtils.createByteBuffer(Short.MAX_VALUE); + try { + ReflectionUtils.setFinalFieldValue(Keyboard.class, aKeyDownBuffer.getName(), aNewByteBuffer); + FMLRelaunchLog.log("[GT++ ASM] LWJGL Keybinding index out of bounds fix", Level.INFO, "Patched Field: "+aKeyDownBuffer.getName()); + } + catch (Throwable t) { + FMLRelaunchLog.log("[GT++ ASM] LWJGL Keybinding index out of bounds fix", Level.INFO, "Failed Patching Field: "+aKeyDownBuffer.getName()); + } + } + init = true; + } + } + + + /** + * Gets a key's name + * @param key The key + * @return a String with the key's human readable name in it or null if the key is unnamed + */ + public static synchronized String getKeyName(int key) { + return ClassTransformer_LWJGL_Keyboard.getKeyName(key); + } + + + + + /** + * Represents a key or mouse button as a string. Args: key + */ + public static String getKeyDisplayString(int aKeyValue) { + return aKeyValue < 0 ? I18n.format("key.mouseButton", new Object[] {Integer.valueOf(aKeyValue + 101)}): getKeyName(aKeyValue); + } + +} |