diff --git a/src/Client/JClassPatcher.java b/src/Client/JClassPatcher.java index 1e0a4438..fcb46363 100644 --- a/src/Client/JClassPatcher.java +++ b/src/Client/JClassPatcher.java @@ -18,7 +18,6 @@ */ package Client; -import Client.Settings.Dir; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; @@ -34,6 +33,7 @@ import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldInsnNode; import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.FrameNode; import org.objectweb.asm.tree.IincInsnNode; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.IntInsnNode; @@ -47,6 +47,7 @@ import org.objectweb.asm.util.Printer; import org.objectweb.asm.util.Textifier; import org.objectweb.asm.util.TraceMethodVisitor; +import Client.Settings.Dir; /** Singleton class which hooks variables and patches classes. */ public class JClassPatcher { @@ -162,7 +163,7 @@ private void patchGeneric(ClassNode node) { hookClassVariable( methodNode, "e", - "Ob", + "x", "Ljava/lang/String;", "Game/Client", "pm_enteredText", @@ -172,7 +173,7 @@ private void patchGeneric(ClassNode node) { hookClassVariable( methodNode, "client", - "Ob", + "x", "Ljava/lang/String;", "Game/Client", "pm_enteredText", @@ -182,7 +183,7 @@ private void patchGeneric(ClassNode node) { hookClassVariable( methodNode, "e", - "x", + "Ob", "Ljava/lang/String;", "Game/Client", "pm_text", @@ -192,13 +193,54 @@ private void patchGeneric(ClassNode node) { hookClassVariable( methodNode, "client", - "x", + "Ob", "Ljava/lang/String;", "Game/Client", "pm_text", "Ljava/lang/String;", true, true); + + hookClassVariable( + methodNode, + "e", + "e", + "Ljava/lang/String;", + "Game/Client", + "modal_enteredText", + "Ljava/lang/String;", + true, + true); + hookClassVariable( + methodNode, + "client", + "e", + "Ljava/lang/String;", + "Game/Client", + "modal_enteredText", + "Ljava/lang/String;", + true, + true); + hookClassVariable( + methodNode, + "e", + "Cb", + "Ljava/lang/String;", + "Game/Client", + "modal_text", + "Ljava/lang/String;", + true, + true); + hookClassVariable( + methodNode, + "client", + "Cb", + "Ljava/lang/String;", + "Game/Client", + "modal_text", + "Ljava/lang/String;", + true, + true); hookClassVariable( methodNode, @@ -210,6 +252,17 @@ private void patchGeneric(ClassNode node) { "Ljava/lang/Object;", true, false); + + hookClassVariable( + methodNode, + "client", + "Xb", + "Ljava/awt/Graphics;", + "Game/Renderer", + "graphicsInstance", + "Ljava/awt/Graphics;", + true, + false); hookClassVariable(methodNode, "ba", "u", "I", "Game/Renderer", "width", "I", false, true); hookClassVariable(methodNode, "ba", "k", "I", "Game/Renderer", "height", "I", false, true); @@ -281,6 +334,8 @@ private void patchGeneric(ClassNode node) { methodNode, "client", "Wd", "I", "Game/Renderer", "width", "I", false, true); hookClassVariable( methodNode, "client", "Oi", "I", "Game/Renderer", "height_client", "I", false, true); + hookClassVariable( + methodNode, "client", "tg", "I", "Game/Renderer", "sprite_media", "I", true, false); hookClassVariable(methodNode, "e", "m", "I", "Game/Renderer", "width", "I", false, true); hookClassVariable(methodNode, "e", "a", "I", "Game/Renderer", "height", "I", false, true); @@ -1025,6 +1080,26 @@ private void patchClient(ClassNode node) { break; } } + + insnNodeList = methodNode.instructions.iterator(); + while (insnNodeList.hasNext()) { + AbstractInsnNode insnNode = insnNodeList.next(); + if (insnNode.getOpcode() == Opcodes.INVOKESPECIAL + && ((MethodInsnNode) insnNode).name.equals("t") + && ((MethodInsnNode) insnNode).desc.equals("(I)V")) { + //draw any extra panels when stating game + VarInsnNode call = (VarInsnNode) insnNode.getNext(); + methodNode.instructions.insertBefore( + call, + new MethodInsnNode( + Opcodes.INVOKESTATIC, + "Game/Client", + "initCreateExtraPanelsHook", + "()V", + false)); + break; + } + } } // handlePacket if (methodNode.name.equals("a") && methodNode.desc.equals("(III)V")) { @@ -1241,6 +1316,44 @@ private void patchClient(ClassNode node) { } } } + + insnNodeList = methodNode.instructions.iterator(); + + while (insnNodeList.hasNext()) { + AbstractInsnNode insnNode = insnNodeList.next(); + AbstractInsnNode nextNode = insnNode.getNext(); + AbstractInsnNode twoNextNode = nextNode.getNext(); + + if (nextNode == null || twoNextNode == null) break; + + if (insnNode.getOpcode() == Opcodes.ICONST_0 + && nextNode.getOpcode() == Opcodes.ISTORE + && ((VarInsnNode) nextNode).var == 2) { + LabelNode label = new LabelNode(); + InsnNode call = (InsnNode) insnNode; + + methodNode.instructions.insertBefore(call, new VarInsnNode(Opcodes.ALOAD, 0)); + methodNode.instructions.insertBefore( + call, new FieldInsnNode(Opcodes.GETFIELD, "client", "Bb", "I")); + methodNode.instructions.insertBefore(call, new VarInsnNode(Opcodes.ALOAD, 0)); + methodNode.instructions.insertBefore( + call, new FieldInsnNode(Opcodes.GETFIELD, "client", "xb", "I")); + methodNode.instructions.insertBefore(call, new VarInsnNode(Opcodes.ALOAD, 0)); + methodNode.instructions.insertBefore( + call, new FieldInsnNode(Opcodes.GETFIELD, "client", "Qb", "I")); + methodNode.instructions.insertBefore(call, new VarInsnNode(Opcodes.ALOAD, 0)); + methodNode.instructions.insertBefore( + call, new FieldInsnNode(Opcodes.GETFIELD, "client", "I", "I")); + methodNode.instructions.insertBefore( + call, + new MethodInsnNode( + Opcodes.INVOKESTATIC, "Game/Client", "gameInputHook", "(IIII)Z", false)); + methodNode.instructions.insertBefore(call, new JumpInsnNode(Opcodes.IFGT, label)); + methodNode.instructions.insertBefore(call, new InsnNode(Opcodes.RETURN)); + methodNode.instructions.insertBefore(call, label); + break; + } + } insnNodeList = methodNode.instructions.iterator(); @@ -1771,6 +1884,30 @@ private void patchClient(ClassNode node) { break; } } + + //conditionally render any new panels? + insnNodeList = methodNode.instructions.iterator(); + while (insnNodeList.hasNext()) { + AbstractInsnNode insnNode = insnNodeList.next(); + AbstractInsnNode nextNode = insnNode.getNext(); + + if (insnNode.getOpcode() == Opcodes.ALOAD + && ((VarInsnNode) insnNode).var == 0 + && nextNode.getOpcode() == Opcodes.GETFIELD + && ((FieldInsnNode) nextNode).name.equals("Qk")) { + LabelNode label = new LabelNode(); + VarInsnNode call = (VarInsnNode) insnNode; + + methodNode.instructions.insertBefore( + call, + new MethodInsnNode( + Opcodes.INVOKESTATIC, "Game/Client", "drawGameHook", "()Z", false)); + methodNode.instructions.insertBefore(call, new JumpInsnNode(Opcodes.IFGT, label)); + methodNode.instructions.insertBefore(call, new InsnNode(Opcodes.RETURN)); + methodNode.instructions.insertBefore(call, label); + break; + } + } } if (methodNode.name.equals("a") && methodNode.desc.equals("(IIZ)Z")) { Iterator insnNodeList = methodNode.instructions.iterator(); @@ -2240,6 +2377,34 @@ else if (pos == 1) { "([Ljava/lang/String;I)V")); } } + + + //hook onto some "other" opcode received + insnNodeList = methodNode.instructions.iterator(); + while (insnNodeList.hasNext()) { + AbstractInsnNode insnNode = insnNodeList.next(); + AbstractInsnNode nextNode = insnNode.getNext(); + LabelNode label = new LabelNode(); + + if (nextNode == null) continue; + if (insnNode.getOpcode() == Opcodes.LDC + && insnNode instanceof LdcInsnNode + && ((LdcInsnNode) insnNode).cst instanceof Integer + && ((Integer) ((LdcInsnNode) insnNode).cst).equals(2097151) + && nextNode.getOpcode() == Opcodes.ACONST_NULL) { + LdcInsnNode call = (LdcInsnNode) insnNode; + methodNode.instructions.insertBefore(call, new VarInsnNode(Opcodes.ILOAD, 1)); + methodNode.instructions.insertBefore(call, new VarInsnNode(Opcodes.ILOAD, 3)); + methodNode.instructions.insertBefore( + call, + new MethodInsnNode( + Opcodes.INVOKESTATIC, "Game/Client", "newOpcodeReceivedHook", "(II)Z", false)); + methodNode.instructions.insertBefore(call, new JumpInsnNode(Opcodes.IFGT, label)); + methodNode.instructions.insertBefore(call, new InsnNode(Opcodes.RETURN)); + methodNode.instructions.insertBefore(call, label); + break; + } + } } // hook onto selected menu option if (methodNode.name.equals("G") && methodNode.desc.equals("(I)V")) { @@ -2355,20 +2520,6 @@ else if (pos == 1) { && prevNode.getOpcode() == Opcodes.GETFIELD && ((FieldInsnNode) prevNode).owner.equals("client") && ((FieldInsnNode) prevNode).name.equals("ge")) { - methodNode.instructions.insertBefore(prevNode, new VarInsnNode(Opcodes.ALOAD, 0)); - methodNode.instructions.insertBefore(prevNode, new TypeInsnNode(Opcodes.NEW, "qa")); - methodNode.instructions.insertBefore(prevNode, new InsnNode(Opcodes.DUP)); - methodNode.instructions.insertBefore(prevNode, new VarInsnNode(Opcodes.ALOAD, 0)); - methodNode.instructions.insertBefore( - prevNode, new FieldInsnNode(Opcodes.GETFIELD, "client", "li", "Lba;")); - methodNode.instructions.insertBefore(prevNode, new IntInsnNode(Opcodes.BIPUSH, 50)); - methodNode.instructions.insertBefore( - prevNode, - new MethodInsnNode(Opcodes.INVOKESPECIAL, "qa", "", "(Lua;I)V", false)); - methodNode.instructions.insertBefore( - prevNode, - new FieldInsnNode( - Opcodes.PUTSTATIC, "Game/Client", "panelRegister", "Ljava/lang/Object;")); methodNode.instructions.insertBefore(prevNode, new VarInsnNode(Opcodes.ILOAD, 1)); methodNode.instructions.insertBefore( prevNode, @@ -2381,6 +2532,34 @@ else if (pos == 1) { break; } } + + // Another hook to get added "I've lost my password" + insnNodeList = methodNode.instructions.iterator(); + + while (insnNodeList.hasNext()) { + AbstractInsnNode insnNode = insnNodeList.next(); + AbstractInsnNode nextNode = insnNode.getNext(); + + if (nextNode == null) break; + + if (insnNode.getOpcode() == Opcodes.INVOKEVIRTUAL + && nextNode.getOpcode() == Opcodes.PUTFIELD + && ((FieldInsnNode) nextNode).owner.equals("client") + && ((FieldInsnNode) nextNode).name.equals("Xi")) { + AbstractInsnNode call = nextNode.getNext(); + methodNode.instructions.insertBefore(call, new VarInsnNode(Opcodes.ILOAD, 1)); + methodNode.instructions.insertBefore(call, new VarInsnNode(Opcodes.ILOAD, 2)); + methodNode.instructions.insertBefore( + call, + new MethodInsnNode( + Opcodes.INVOKESTATIC, + "Game/AccountManagement", + "panel_login_hook", + "(II)V", + false)); + break; + } + } } if (methodNode.name.equals("k") && methodNode.desc.equals("(I)V")) { // pre-game display hook @@ -2458,8 +2637,54 @@ else if (pos == 1) { "account_panels_key_hook", "(II)V", false)); + break; } } + + insnNodeList = methodNode.instructions.iterator(); + + while (insnNodeList.hasNext()) { + AbstractInsnNode insnNode = insnNodeList.next(); + AbstractInsnNode nextNode = insnNode.getNext(); + AbstractInsnNode twoNextNode = nextNode.getNext(); + AbstractInsnNode findNode, nextFindNode, call; + LabelNode labelNode, exitNode; + + if (nextNode == null || twoNextNode == null) break; + + if (insnNode.getOpcode() == Opcodes.ALOAD + && ((VarInsnNode) insnNode).var == 0 + && nextNode.getOpcode() == Opcodes.GETFIELD + && ((FieldInsnNode) nextNode).name.equals("qg") + && twoNextNode.getOpcode() == Opcodes.ICONST_M1) { + + findNode = twoNextNode; + while (findNode.getOpcode() != Opcodes.IF_ICMPEQ) { + // find part of checking is logged in + findNode = findNode.getNext(); + } + nextFindNode = findNode.getNext(); + + labelNode = ((JumpInsnNode)findNode).label; + exitNode = ((JumpInsnNode)nextFindNode).label; + call = insnNode.getPrevious(); + + methodNode.instructions.insertBefore(call, new VarInsnNode(Opcodes.ALOAD, 0)); + methodNode.instructions.insertBefore( + call, new FieldInsnNode(Opcodes.GETFIELD, "client", "qg", "I")); + methodNode.instructions.insertBefore(call, new VarInsnNode(Opcodes.ILOAD, 2)); + methodNode.instructions.insertBefore( + call, + new MethodInsnNode( + Opcodes.INVOKESTATIC, + "Game/AccountManagement", + "ingame_keyhandler_hook", + "(II)I")); + methodNode.instructions.insertBefore(insnNode, new JumpInsnNode(Opcodes.IFNE, exitNode)); + + break; + } + } } if (methodNode.name.equals("x") && methodNode.desc.equals("(I)V")) { // Login button press hook, from login panel @@ -2484,6 +2709,34 @@ else if (pos == 1) { methodNode.instructions.insertBefore( findNode, new MethodInsnNode(Opcodes.INVOKESTATIC, "Game/Client", "login_hook", "()V", false)); + + + // Lost password press hook, from login panel + insnNodeList = methodNode.instructions.iterator(); + + while (insnNodeList.hasNext()) { + AbstractInsnNode insnNode = insnNodeList.next(); + AbstractInsnNode nextNode = insnNode.getNext(); + AbstractInsnNode twoNextNode = nextNode.getNext(); + LabelNode label = new LabelNode(); + + if (nextNode == null || twoNextNode == null) break; + + if (insnNode.getOpcode() == Opcodes.GETFIELD + && ((FieldInsnNode) insnNode).name.equals("Ih") + && nextNode.getOpcode() == Opcodes.BIPUSH + && ((IntInsnNode) nextNode).operand == -88 + && twoNextNode.getOpcode() == Opcodes.INVOKEVIRTUAL) { + + FrameNode call = (FrameNode) (twoNextNode.getNext().getNext()); + methodNode.instructions.insertBefore( + call, + new MethodInsnNode( + Opcodes.INVOKESTATIC, "Game/Client", "loginOtherButtonCheckHook", "()V", false)); + break; + } + } + // Register button press hook insnNodeList = methodNode.instructions.iterator(); @@ -2552,7 +2805,6 @@ else if (pos == 1) { methodNode.instructions.insertBefore(insnNode, new VarInsnNode(Opcodes.ALOAD, 0)); methodNode.instructions.insertBefore( insnNode, new FieldInsnNode(Opcodes.GETFIELD, "client", "xb", "I")); - methodNode.instructions.insertBefore(insnNode, new IntInsnNode(Opcodes.SIPUSH, -9989)); methodNode.instructions.insertBefore(insnNode, new VarInsnNode(Opcodes.ALOAD, 0)); methodNode.instructions.insertBefore( insnNode, new FieldInsnNode(Opcodes.GETFIELD, "client", "Qb", "I")); @@ -2565,11 +2817,141 @@ else if (pos == 1) { Opcodes.INVOKESTATIC, "Game/AccountManagement", "account_panels_input_hook", - "(IIIII)V", + "(IIII)V", false)); } } } + if (methodNode.name.equals("b") && methodNode.desc.equals("(IZ)V")) { + // Options menu hook + Iterator insnNodeList = methodNode.instructions.iterator(); + + while (insnNodeList.hasNext()) { + AbstractInsnNode insnNode = insnNodeList.next(); + AbstractInsnNode nextNode = insnNode.getNext(); + AbstractInsnNode startNode; + AbstractInsnNode targetNode; + + if (nextNode == null) break; + + if (insnNode.getOpcode() == Opcodes.SIPUSH && ((IntInsnNode) insnNode).operand == 145) { + startNode = targetNode = insnNode; + while (startNode.getOpcode() != Opcodes.ALOAD) { + // find aload0, to insert jump to skip "To change your contact details,password, + // recovery questions, etc..please select 'account management'" + startNode = startNode.getPrevious(); + } + + while (targetNode.getOpcode() != Opcodes.SIPUSH + || ((IntInsnNode) targetNode).operand != 139) { + // find "Privacy settings. Will be applied to" keymarker to indicate block to jump to + targetNode = targetNode.getNext(); + } + // back off to find the corresponding aload0 + while (targetNode.getOpcode() != Opcodes.ALOAD) { + targetNode = targetNode.getPrevious(); + } + + LabelNode label = new LabelNode(); + + methodNode.instructions.insertBefore( + startNode, + new MethodInsnNode( + Opcodes.INVOKESTATIC, "Game/Client", "showSecuritySettings", "()Z")); + methodNode.instructions.insertBefore(startNode, new JumpInsnNode(Opcodes.IFGT, label)); + + methodNode.instructions.insertBefore(targetNode, label); + methodNode.instructions.insertBefore(targetNode, new VarInsnNode(Opcodes.ILOAD, 6)); + methodNode.instructions.insertBefore(targetNode, new VarInsnNode(Opcodes.ILOAD, 7)); + methodNode.instructions.insertBefore(targetNode, new VarInsnNode(Opcodes.ALOAD, 0)); + methodNode.instructions.insertBefore( + targetNode, new FieldInsnNode(Opcodes.GETFIELD, "client", "I", "I")); + methodNode.instructions.insertBefore(targetNode, new VarInsnNode(Opcodes.ALOAD, 0)); + methodNode.instructions.insertBefore( + targetNode, new FieldInsnNode(Opcodes.GETFIELD, "client", "xb", "I")); + methodNode.instructions.insertBefore( + targetNode, + new MethodInsnNode( + Opcodes.INVOKESTATIC, + "Game/AccountManagement", + "options_security_hook", + "(IIII)I")); + methodNode.instructions.insertBefore(targetNode, new VarInsnNode(Opcodes.ILOAD, 7)); + methodNode.instructions.insertBefore(targetNode, new InsnNode(Opcodes.IADD)); + methodNode.instructions.insertBefore(targetNode, new VarInsnNode(Opcodes.ISTORE, 7)); + + break; + } + } + + insnNodeList = methodNode.instructions.iterator(); + + while (insnNodeList.hasNext()) { + AbstractInsnNode insnNode = insnNodeList.next(); + AbstractInsnNode nextNode = insnNode.getNext(); + AbstractInsnNode twoNextNode = nextNode.getNext(); + AbstractInsnNode startNode; + AbstractInsnNode targetNode; + AbstractInsnNode call; + + if (nextNode == null || twoNextNode == null) break; + + if (insnNode.getOpcode() == Opcodes.IINC + && ((IincInsnNode) insnNode).var == 7 + && ((IincInsnNode) insnNode).incr == 15 + && nextNode.getOpcode() == Opcodes.IINC + && ((IincInsnNode) nextNode).var == 7 + && ((IincInsnNode) nextNode).incr == 15 + && twoNextNode.getOpcode() == Opcodes.IINC + && ((IincInsnNode) twoNextNode).var == 7 + && ((IincInsnNode) twoNextNode).incr == 15) { + // start part of for clicking "To change your contact details,password, recovery + // questions, etc..please select 'account management'" + startNode = targetNode = insnNode; + + while (targetNode.getOpcode() != Opcodes.IINC + || ((IincInsnNode) targetNode).incr != 35 + || targetNode.getNext().getOpcode() != Opcodes.ICONST_0) { + // find part close to click "Privacy settings. Will be applied to" + targetNode = targetNode.getNext(); + } + targetNode = targetNode.getNext(); // iconst0 + + LabelNode label = new LabelNode(); + + methodNode.instructions.insertBefore( + startNode, + new MethodInsnNode( + Opcodes.INVOKESTATIC, "Game/Client", "showSecuritySettings", "()Z")); + methodNode.instructions.insertBefore(startNode, new JumpInsnNode(Opcodes.IFGT, label)); + + methodNode.instructions.insertBefore(targetNode, label); + methodNode.instructions.insertBefore(targetNode, new VarInsnNode(Opcodes.ILOAD, 6)); + methodNode.instructions.insertBefore(targetNode, new VarInsnNode(Opcodes.ILOAD, 7)); + methodNode.instructions.insertBefore(targetNode, new VarInsnNode(Opcodes.ALOAD, 0)); + methodNode.instructions.insertBefore( + targetNode, new FieldInsnNode(Opcodes.GETFIELD, "client", "I", "I")); + methodNode.instructions.insertBefore(targetNode, new VarInsnNode(Opcodes.ALOAD, 0)); + methodNode.instructions.insertBefore( + targetNode, new FieldInsnNode(Opcodes.GETFIELD, "client", "xb", "I")); + methodNode.instructions.insertBefore(targetNode, new VarInsnNode(Opcodes.ALOAD, 0)); + methodNode.instructions.insertBefore( + targetNode, new FieldInsnNode(Opcodes.GETFIELD, "client", "Cf", "I")); + methodNode.instructions.insertBefore( + targetNode, + new MethodInsnNode( + Opcodes.INVOKESTATIC, + "Game/AccountManagement", + "options_security_click_hook", + "(IIIII)I")); + methodNode.instructions.insertBefore(targetNode, new VarInsnNode(Opcodes.ILOAD, 7)); + methodNode.instructions.insertBefore(targetNode, new InsnNode(Opcodes.IADD)); + methodNode.instructions.insertBefore(targetNode, new VarInsnNode(Opcodes.ISTORE, 7)); + + break; + } + } + } if (methodNode.name.equals("a") && methodNode.desc.equals("(ZI)V")) { // Disconnect hook (::closecon) Iterator insnNodeList = methodNode.instructions.iterator(); @@ -2907,6 +3289,64 @@ else if (pos == 1) { } } + if (methodNode.name.equals("I") && methodNode.desc.equals("(I)V")) { + // menu ui + Iterator insnNodeList = methodNode.instructions.iterator(); + while (insnNodeList.hasNext()) { + AbstractInsnNode insnNode = insnNodeList.next(); + AbstractInsnNode nextNode = insnNode.getNext(); + AbstractInsnNode findNode; + LabelNode targetNode; + LabelNode labelNode; + + if (nextNode == null) break; + + if (insnNode.getOpcode() == Opcodes.INVOKESPECIAL + && ((MethodInsnNode) insnNode).name.equals("d") + && ((MethodInsnNode) insnNode).desc.equals("(B)V") + && nextNode.getOpcode() == Opcodes.ILOAD + && ((VarInsnNode) nextNode).var == 4) { + findNode = nextNode.getNext(); + targetNode = ((JumpInsnNode) findNode).label; + + // find last else to insert else if + while (findNode.getOpcode() != Opcodes.ICONST_1 + || findNode.getNext().getOpcode() != Opcodes.ISTORE) { + findNode = findNode.getNext(); + } + + labelNode = new LabelNode(); + methodNode.instructions.insertBefore(findNode, labelNode); + + methodNode.instructions.insertBefore( + labelNode, + new FieldInsnNode( + Opcodes.GETSTATIC, "Game/AccountManagement", "panelPasswordChangeMode", "I")); + methodNode.instructions.insertBefore( + labelNode, new JumpInsnNode(Opcodes.IFEQ, labelNode)); + methodNode.instructions.insertBefore(labelNode, new VarInsnNode(Opcodes.ALOAD, 0)); + methodNode.instructions.insertBefore( + labelNode, new FieldInsnNode(Opcodes.GETFIELD, "client", "I", "I")); + methodNode.instructions.insertBefore(labelNode, new VarInsnNode(Opcodes.ALOAD, 0)); + methodNode.instructions.insertBefore( + labelNode, new FieldInsnNode(Opcodes.GETFIELD, "client", "xb", "I")); + methodNode.instructions.insertBefore(labelNode, new VarInsnNode(Opcodes.ALOAD, 0)); + methodNode.instructions.insertBefore( + labelNode, new FieldInsnNode(Opcodes.GETFIELD, "client", "Cf", "I")); + methodNode.instructions.insertBefore( + labelNode, + new MethodInsnNode( + Opcodes.INVOKESTATIC, + "Game/AccountManagement", + "draw_change_pass_hook", + "(III)V", + false)); + methodNode.instructions.insertBefore( + labelNode, new JumpInsnNode(Opcodes.GOTO, targetNode)); + } + } + } + // hookTracer(node, methodNode); } } diff --git a/src/Client/Util.java b/src/Client/Util.java index 1c411948..e0df68ae 100644 --- a/src/Client/Util.java +++ b/src/Client/Util.java @@ -18,8 +18,6 @@ */ package Client; -import Game.Replay; -import Game.ReplayQueue; import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.File; @@ -32,6 +30,8 @@ import java.util.Locale; import java.util.zip.CRC32; import java.util.zip.GZIPInputStream; +import Game.Replay; +import Game.ReplayQueue; /** A miscellaneous utility class */ public class Util { @@ -415,4 +415,17 @@ public static void int_put(byte[] buffer, int offset, int num) { buffer[offset + 2] = (byte) (num >> 8); buffer[offset + 3] = (byte) num; } + + /** RSC175 - format a string to only have letters and numbers, with maxlength */ + public static String formatString(String s, int maxLen) { + String lowerString = s.toLowerCase(); + String res = ""; + for (int i = 0; i < lowerString.length() && i < maxLen; ++i) { + char ch = lowerString.charAt(i); + if (ch >= 'a' && ch <= 'z' || ch >= '0' && ch <= '9') { + res = String.valueOf(res) + ch; + } + } + return res; + } } diff --git a/src/Game/AccountManagement.java b/src/Game/AccountManagement.java index d71418be..fba7ec24 100644 --- a/src/Game/AccountManagement.java +++ b/src/Game/AccountManagement.java @@ -18,14 +18,23 @@ */ package Game; +import java.math.BigInteger; import Client.CRC16; import Client.Logger; import Client.Settings; import Client.Util; -import java.math.BigInteger; public class AccountManagement { + public static int panelPasswordChangeMode; + public static String oldPassword; + public static String newPassword; + public static int customQuestionEntry = -1; + + public static String recoveryQuestions[] = new String[]{"Where were you born?", "What was your first teachers name?", "What is your fathers middle name?", "Who was your first best friend?", "What is your favourite vacation spot?", "What is your mothers middle name?", "What was your first pets name?", "What was the name of your first school?", "What is your mothers maiden name?", "Who was your first boyfriend/girlfriend?", "What was the first computer game you purchased?", "Who is your favourite actor/actress?", "Who is your favourite author?", "Who is your favourite musician?", "Who is your favourite cartoon character?", "What is your favourite book?", "What is your favourite food?", "What is your favourite movie?"}; + public static int recoveryIndices[] = new int[] { 0, 1, 2, 3, 4 }; + + // § SECTION stream IO interaction § public static void register(String user, String pass) { @@ -48,7 +57,7 @@ public static void register(String user, String pass) { StreamUtil.initializeStream(Client.server_address, port); StreamUtil.setStreamMaxRetries(Client.maxRetries); - int session_id = 0; // TODO: should read session ID here, triggered by TCP handshake + Client.session_id = 0; // TODO: should read int to get session ID here, triggered by TCP handshake StreamUtil.newPacket(2); Object buffer = StreamUtil.getStreamBuffer(); @@ -59,7 +68,7 @@ public static void register(String user, String pass) { StreamUtil.putLongTo(buffer, formatUser); // Put Password - enc_cred_put(buffer, formatPass, session_id); + enc_cred_put(buffer, formatPass, Client.session_id); // In 235 putRandom of "random.dat" is 24 bytes, but for 127 is expected 4 bytes. Object randBlock = StreamUtil.getNewBuffer(24); @@ -114,6 +123,222 @@ public static void register(String user, String pass) { } } } + + public static void forgotPass(String user) { + Client.setLoginMessage("Connecting to server", "Please wait..."); + + try { + int port = Replay.connection_port; + StreamUtil.initializeStream(Client.server_address, port); + StreamUtil.setStreamMaxRetries(Client.maxRetries); + + Client.session_id = 0; // TODO: should read int to get session ID here, triggered by TCP handshake + + StreamUtil.newPacket(4); + Object buffer = StreamUtil.getStreamBuffer(); + StreamUtil.putLongTo(buffer, Util.username2hash(user)); + StreamUtil.flushPacket(); + + StreamUtil.readShort(); // Unknown what data this contained, client doesn't use it. + int response = StreamUtil.readStream(); + Logger.Game("Getpq response: " + response); + if (response == 0) { + Client.setLoginMessage("", "Sorry, the recovery questions for this user have not been set"); + return; + } + + String question; + int idx; + for (int var12 = 0; var12 < 5; ++var12) { + int length = StreamUtil.readStream(); + byte[] arr = new byte[5000]; + StreamUtil.readBytes(arr, length); + question = new String(arr, 0, length); + + if (question.startsWith("~:")) { + question = question.substring(2); + idx = 0; + + try { + idx = Integer.parseInt(question); + } catch (Exception var8) { } + + question = recoveryQuestions[idx]; + } + + Panel.setControlText(Client.panelRecovery, Client.controlRecoveryQuestion[var12], question); + } + + if (Client.failedRecovery) { + Client.setLoginMessage("", "Sorry, you have already attempted 1 recovery, try again later"); + return; + } + + Client.login_screen = Client.SCREEN_PASSWORD_RECOVERY; + Panel.setControlText(Client.panelRecovery, Client.controlRecovery1, + "@yel@To prove this is your account please provide the answers to"); + Panel.setControlText(Client.panelRecovery, Client.controlRecovery2, + "@yel@your security questions. You will then be able to reset your password"); + + for (int i = 0; i < 5; ++i) { + Panel.setControlText(Client.panelRecovery, Client.controlRecoveryInput[i], ""); + } + + Panel.setControlText(Client.panelRecovery, Client.recoverOldPassInput, ""); + Panel.setControlText(Client.panelRecovery, Client.recoverNewPassInput, ""); + Panel.setControlText(Client.panelRecovery, Client.recoverConfirmPassInput, ""); + return; + } catch (Exception e) { + Client.setLoginMessage("Check your internet settings", "Sorry! Unable to connect to server."); + return; + } + } + + public static void recover() { + Client.setLoginMessage("Connecting to server", "Please wait..."); + + try { + int port = Replay.connection_port; + StreamUtil.initializeStream(Client.server_address, port); + StreamUtil.setStreamMaxRetries(Client.maxRetries); + + Client.session_id = 0; // TODO: should read int to get session ID here, triggered by TCP handshake + + String oldPass = Client.formatText(Panel.getControlText(Client.panelRecovery, Client.recoverOldPassInput), 20); + String newPass = Client.formatText(Panel.getControlText(Client.panelRecovery, Client.recoverNewPassInput), 20); + + StreamUtil.newPacket(8); + Object buffer = StreamUtil.getStreamBuffer(); + StreamUtil.putLongTo(buffer, Util.username2hash(Panel.getControlText(Client.panelLogin, Client.loginUserInput))); + + // In 235 putRandom of "random.dat" is 24 bytes, but for 127 is expected 4 bytes. + Object randBlock = StreamUtil.getNewBuffer(24); + StreamUtil.putRandom(randBlock); + byte[] randArr = StreamUtil.getBufferByteArray(randBlock); + CRC16 sum = new CRC16(); + sum.update(randArr); + int rand = (int) sum.getValue(); + StreamUtil.putIntTo(buffer, rand); + + enc_cred_put(buffer, oldPass + newPass, Client.session_id); + + for (int i=0; i < 5; ++i) { + /** In RSC127 it would have sent an encrypted "hash" like of answers, but seems in later revisions + * incl. up to RSC175 was changed to just send the encrypted answers, probably due to collisions + * in RSC127 hasher function */ + String answer = Panel.getControlText(Client.panelRecovery, Client.controlRecoveryInput[i]); + answer = Util.formatString(answer, 50); + StreamUtil.putByteTo(buffer, (byte)answer.length()); + enc_cred_put(buffer, answer, Client.session_id); + } + + StreamUtil.flushPacket(); + + StreamUtil.readStream(); // Unknown what data this contained, client doesn't use it. + int response = StreamUtil.readStream(); + Logger.Game("Recover response: " + response); + if (response == 0) { + Client.login_screen = Client.SCREEN_USERNAME_PASSWORD_LOGIN; + Client.setLoginMessage("", "Sorry, recovery failed. You may try again in 1 hour"); + Client.failedRecovery = true; + return; + } + + if (response == 1) { + Client.login_screen = Client.SCREEN_USERNAME_PASSWORD_LOGIN; + Client.setLoginMessage("", "Your pass has been reset. You may now use the new pass to login"); + return; + } + + Client.login_screen = Client.SCREEN_USERNAME_PASSWORD_LOGIN; + Client.setLoginMessage("", "Recovery failed! Attempts exceeded?"); + return; + } catch (Exception e) { + e.printStackTrace(); + Client.setLoginMessage("Check your internet settings", "Sorry! Unable to connect to server."); + } + } + + public static void sendPassChange(String oldPwd, String newPwd) { + String oldPass = Client.formatText(oldPwd, 20); + String newPass = Client.formatText(newPwd, 20); + + StreamUtil.newPacket(25); + + Object buffer = StreamUtil.getStreamBuffer(); + enc_cred_put(buffer, oldPass + newPass, Client.session_id); + + StreamUtil.sendPacket(); + } + + public static void sendRecoveryQuestions() { + StreamUtil.newPacket(208); + Object buffer = StreamUtil.getStreamBuffer(); + + for (int idx = 0; idx < 5; ++idx) { + String question = Client.controlRecoveryText[idx]; + if (question == null || question.length() == 0) { + question = String.valueOf(idx + 1); + } + if (question.length() > 50) { + question = question.substring(0, 50); + } + String answer = Panel.getControlText(Client.panelRecoveryQuestions, Client.controlAnswerInput[idx]); + answer = Util.formatString(answer, 50); + + StreamUtil.putByteTo(buffer, (byte)question.length()); + StreamUtil.putStrTo(buffer, question); + /** In RSC127 it would have sent an encrypted "hash" like of answers, but seems in later revisions + * incl. up to RSC175 was changed to just send the encrypted answers, probably due to collisions + * in RSC127 hasher function */ + StreamUtil.putByteTo(buffer, (byte)answer.length()); + enc_cred_put(buffer, answer, Client.session_id); + } + + StreamUtil.sendPacket(); + } + + public static void sendContactDetails(String fullName, String zipCode, String country, String email) { + StreamUtil.newPacket(253); + Object buffer = StreamUtil.getStreamBuffer(); + + StreamUtil.putByteTo(buffer, (byte)fullName.length()); + StreamUtil.putStrTo(buffer, fullName); + StreamUtil.putByteTo(buffer, (byte)zipCode.length()); + StreamUtil.putStrTo(buffer, zipCode); + StreamUtil.putByteTo(buffer, (byte)country.length()); + StreamUtil.putStrTo(buffer, country); + StreamUtil.putByteTo(buffer, (byte)email.length()); + StreamUtil.putStrTo(buffer, email); + + StreamUtil.sendPacket(); + } + + public static boolean processPacket(int opcode, int psize) { + boolean processed = false; + if (Settings.SHOW_ACCOUNT_SECURITY_SETTINGS.get(Settings.currentProfile)) { + if (opcode == 224) { + Client.showRecoveryQuestions = true; + for (int idx = 0; idx < 5; ++idx) { + recoveryIndices[idx] = idx; + Client.controlRecoveryText[idx] = recoveryQuestions[recoveryIndices[idx]]; + Panel.setControlText( + Client.panelRecoveryQuestions,Client.controlAnswerInput[idx], ""); + Panel.setControlText( + Client.panelRecoveryQuestions,Client.controlRecoveryIns[idx], idx + 1 + ": " + Client.controlRecoveryText[idx]); + } + processed = true; + } else if (opcode == 232) { + Client.showContactDetails = true; + Panel.setControlText(Client.controlContactDetails, Client.fullNameInput, ""); + Panel.setControlText(Client.controlContactDetails, Client.zipCodeInput, ""); + Panel.setControlText(Client.controlContactDetails, Client.countryInput, ""); + Panel.setControlText(Client.controlContactDetails, Client.emailInput, ""); + processed = true; + } + } + return processed; + } public static void enc_cred_put(Object buffer, String str, int sessionId) { byte[] data = str.getBytes(); @@ -174,6 +399,7 @@ public static void pregame_hook() { Panel.drawPanel(Client.panelRegister); } else if (Client.login_screen == Client.SCREEN_PASSWORD_RECOVERY) { Client.clearScreen(); + Panel.drawPanel(Client.panelRecovery); } } catch (Exception e) { e.printStackTrace(); @@ -186,13 +412,45 @@ public static void response_display_hook(String text1, String text2) { Panel.setControlText(Client.panelRegister, Client.controlRegister, text1 + " " + text2); } - if (Client.login_screen == Client.SCREEN_PASSWORD_RECOVERY) {} + if (Client.login_screen == Client.SCREEN_PASSWORD_RECOVERY) { + Panel.setControlText(Client.panelRecovery, Client.controlRecovery1, text1); + Panel.setControlText(Client.panelRecovery, Client.controlRecovery2, text2); + } // continue checking if == 2 (login screen) with existing code } catch (Exception e) { e.printStackTrace(); } } + + public static boolean pending_render() { + boolean processed = false; + if (Client.showRecoveryQuestions) { + Client.setInterlace(false); + Client.clearScreen(); + Panel.drawPanel(Client.panelRecoveryQuestions); + if (customQuestionEntry != -1) { + int n = 150; + Renderer.drawBox(26, n, 460, 60, 0); + Renderer.drawBoxBorder(26, n, 460, 60, 16777215); + n += 22; + Renderer.drawStringCenter("Please enter your question", 256, n, 4, 16777215); + n += 25; + Renderer.drawStringCenter(Client.pm_enteredText + "*", 256, n, 4, 16777215); + } + //Renderer.drawSprite(0, Renderer.height_client - 4, Renderer.sprite_media + 23); + Client.drawGraphics(); + processed = true; + } else if (Client.showContactDetails) { + Client.setInterlace(false); + Client.clearScreen(); + Panel.drawPanel(Client.panelContactDetails); + //Renderer.drawSprite(0, Renderer.height_client - 4, Renderer.sprite_media + 23); + Client.drawGraphics(); + processed = true; + } + return processed; + } public static void welcome_new_user_hook() { try { @@ -221,6 +479,7 @@ public static void panel_welcome_hook(int n) { Client.registerButton = Panel.addButtonTo(Client.panelWelcome, 86, 40 + 250, 100, 35); } + Client.panelRegister = Panel.createPanel(50); int var1 = 70; Client.controlRegister = Panel.addCenterTextTo( @@ -234,17 +493,17 @@ public static void panel_welcome_hook(int n) { Panel.addButtonBackTo(Client.panelRegister, 256, var2 + 17, 250, 34); Panel.addCenterTextTo(Client.panelRegister, 256, var2 + 8, "Choose a Username", 4, false); Client.chooseUserInput = - Panel.addInputTo(Client.panelRegister, n, 256, var2 + 25, 200, 40, 4, 320, false, false); + Panel.addInputTo(Client.panelRegister, 256, var2 + 25, 200, 40, 4, 320, false, false); Panel.setFocus(Client.panelRegister, Client.chooseUserInput); var2 += 40; Panel.addButtonBackTo(Client.panelRegister, 141, var2 + 17, 220, 34); Panel.addCenterTextTo(Client.panelRegister, 141, var2 + 8, "Choose a Password", 4, false); Client.choosePasswordInput = - Panel.addInputTo(Client.panelRegister, n, 141, var2 + 25, 220, 40, 4, 20, true, false); + Panel.addInputTo(Client.panelRegister, 141, var2 + 25, 220, 40, 4, 20, true, false); Panel.addButtonBackTo(Client.panelRegister, 371, var2 + 17, 220, 34); Panel.addCenterTextTo(Client.panelRegister, 371, var2 + 8, "Confirm Password", 4, false); Client.chooseConfirmPassInput = - Panel.addInputTo(Client.panelRegister, n, 371, var2 + 25, 220, 40, 4, 20, true, false); + Panel.addInputTo(Client.panelRegister, 371, var2 + 25, 220, 40, 4, 20, true, false); var2 += 40; var2 += 20; Client.acceptTermsCheckbox = Panel.addCheckboxTo(Client.panelRegister, 60, var2, 14); @@ -271,20 +530,422 @@ public static void panel_welcome_hook(int n) { e.printStackTrace(); } } + + public static void panel_login_hook(int n, int yPos) { + try { + if (Settings.SHOW_ACCOUNT_SECURITY_SETTINGS.get(Settings.currentProfile)) { + int var2 = yPos + 30; + Panel.addButtonBackTo(Client.panelLogin, 410, var2, 160, 25); + Panel.addCenterTextTo(Client.panelLogin, 410, var2, "I've lost my password", 4, false); + Client.loginLostPasswordButton = Panel.addButtonTo(Client.panelLogin, 410, var2, 160, 25); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void create_account_recovery() { + try { + Client.panelRecovery = Panel.createPanel(100); + int var1_1 = 10; + Client.controlRecovery1 = Panel.addCenterTextTo(Client.panelRecovery, 256, var1_1, "@yel@To prove this is your account please provide the answers to", 1, true); + var1_1 += 15; + Client.controlRecovery2 = Panel.addCenterTextTo(Client.panelRecovery, 256, var1_1, "@yel@your security questions. You will then be able to reset your password", 1, true); + var1_1 += 35; + + for (int var2_2 = 0; var2_2 < 5; ++var2_2) { + Panel.addButtonBackTo(Client.panelRecovery, 256, var1_1, 410, 30); + Client.controlRecoveryQuestion[var2_2] = Panel.addCenterTextTo(Client.panelRecovery, 256, var1_1 - 7, var2_2 + 1 + ": question?", 1, true); + Client.controlRecoveryInput[var2_2] = Panel.addInputTo(Client.panelRecovery, 256, var1_1 + 7, 310, 30, 1, 80, true, true); + var1_1 += 35; + } + + Panel.setFocus(Client.panelRecovery, Client.controlRecoveryInput[0]); + Panel.addButtonBackTo(Client.panelRecovery, 256, var1_1, 410, 30); + Panel.addCenterTextTo(Client.panelRecovery, 256, var1_1 - 7, "If you know it, enter a previous password used on this account", 1, true); + Client.recoverOldPassInput = Panel.addInputTo(Client.panelRecovery, 256, var1_1 + 7, 310, 30, 1, 80, true, true); + var1_1 += 35; + Panel.addButtonBackTo(Client.panelRecovery, 151, var1_1, 200, 30); + Panel.addCenterTextTo(Client.panelRecovery, 151, var1_1 - 7, "Choose a NEW password", 1, true); + Client.recoverNewPassInput = Panel.addInputTo(Client.panelRecovery, 146, var1_1 + 7, 200, 30, 1, 80, true, true); + Panel.addButtonBackTo(Client.panelRecovery, 361, var1_1, 200, 30); + Panel.addCenterTextTo(Client.panelRecovery, 361, var1_1 - 7, "Confirm new password", 1, true); + Client.recoverConfirmPassInput = Panel.addInputTo(Client.panelRecovery, 366, var1_1 + 7, 200, 30, 1, 80, true, true); + var1_1 += 35; + Panel.addButtonBackTo(Client.panelRecovery, 201, var1_1, 100, 30); + Panel.addCenterTextTo(Client.panelRecovery, 201, var1_1, "Submit", 4, true); + Client.chooseSubmitRecoveryButton = Panel.addButtonTo(Client.panelRecovery, 201, var1_1, 100, 30); + Panel.addButtonBackTo(Client.panelRecovery, 311, var1_1, 100, 30); + Panel.addCenterTextTo(Client.panelRecovery, 311, var1_1, "Cancel", 4, true); + Client.chooseCancelRecoveryButton = Panel.addButtonTo(Client.panelRecovery, 311, var1_1, 100, 30); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void create_recovery_questions() { + try { + Client.panelRecoveryQuestions = Panel.createPanel(100); + int var1_1 = 8; + Client.controlRecoveryQuestions = Panel.addCenterTextTo( + Client.panelRecoveryQuestions,256, var1_1, "@yel@Please provide 5 security questions in case you lose your password", 1, true); + var1_1 += 22; + Panel.addCenterTextTo( + Client.panelRecoveryQuestions,256, var1_1, "If you ever lose your password, you will need these to prove you own your account.", 1, true); + var1_1 += 13; + Panel.addCenterTextTo( + Client.panelRecoveryQuestions,256, var1_1, "Your answers are encrypted and are ONLY used for password recovery purposes.", 1, true); + var1_1 += 22; + Panel.addCenterTextTo( + Client.panelRecoveryQuestions,256, var1_1, "@ora@IMPORTANT:@whi@ To recover your password you must give the EXACT same answers you", 1, true); + var1_1 += 13; + Panel.addCenterTextTo( + Client.panelRecoveryQuestions,256, var1_1, "give here. If you think you might forget an answer, or someone else could guess the", 1, true); + var1_1 += 13; + Panel.addCenterTextTo( + Client.panelRecoveryQuestions,256, var1_1, "answer, then press the 'different question' button to get a better question.", 1, true); + var1_1 += 35; + for (int idx = 0; idx < 5; ++idx) { + Panel.addButtonBackTo(Client.panelRecoveryQuestions,170, var1_1, 310, 30); + Client.controlRecoveryText[idx] = recoveryQuestions[recoveryIndices[idx]]; + Client.controlRecoveryIns[idx] = Panel.addCenterTextTo( + Client.panelRecoveryQuestions,170, var1_1 - 7, idx + 1 + ": " + recoveryQuestions[recoveryIndices[idx]], 1, true); + Client.controlAnswerInput[idx] = Panel.addInputTo(Client.panelRecoveryQuestions, 170, var1_1 + 7, 310, 30, 1, 80, false, true); + Panel.addButtonBackTo(Client.panelRecoveryQuestions,370, var1_1, 80, 30); + Panel.addCenterTextTo( + Client.panelRecoveryQuestions,370, var1_1 - 7, "Different", 1, true); + Panel.addCenterTextTo( + Client.panelRecoveryQuestions,370, var1_1 + 7, "Question", 1, true); + Client.controlQuestion[idx] = Panel.addButtonTo(Client.panelRecoveryQuestions,370, var1_1, 80, 30); + Panel.addButtonBackTo(Client.panelRecoveryQuestions,455, var1_1, 80, 30); + Panel.addCenterTextTo( + Client.panelRecoveryQuestions,455, var1_1 - 7, "Enter own", 1, true); + Panel.addCenterTextTo( + Client.panelRecoveryQuestions,455, var1_1 + 7, "Question", 1, true); + Client.controlCustomQuestion[idx] = Panel.addButtonTo(Client.panelRecoveryQuestions,455, var1_1, 80, 30); + var1_1 += 35; + } + Panel.setFocus(Client.panelRecoveryQuestions, Client.controlAnswerInput[0]); + var1_1 += 10; + Panel.addButtonBackTo(Client.panelRecoveryQuestions,256, var1_1, 250, 30); + Panel.addCenterTextTo( + Client.panelRecoveryQuestions,256, var1_1, "Click here when finished", 4, true); + Client.chooseFinishSetRecoveryButton = Panel.addButtonTo(Client.panelRecoveryQuestions,256, var1_1, 250, 30); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void create_contact_details() { + try { + Client.panelContactDetails = Panel.createPanel(100); + int n = 256; + int n2 = 400; + int n3 = 25; + Client.controlContactDetails = + Panel.addCenterTextTo( + Client.panelContactDetails,256, n3, "@yel@Please supply your contact details", 5, true); + n3 += 30; + Panel.addCenterTextTo( + Client.panelContactDetails,256, n3, "We need this information to provide an efficient customer support service ", 1, true); + n3 += 15; + Panel.addCenterTextTo( + Client.panelContactDetails,256, n3, "and also to work out where to locate future RuneScape servers.", 1, true); + n3 += 25; + Panel.addCenterTextTo( + Client.panelContactDetails,256, n3, "We know some people are concerned about entering their email address on", 1, true); + n3 += 15; + Panel.addCenterTextTo( + Client.panelContactDetails,255, n3, "websites, and for this reason we take our users privacy very seriously.", 1, true); + n3 += 15; + Panel.addCenterTextTo( + Client.panelContactDetails,256, n3, "For our full policy please click the relevant link below this game window", 1, true); + Panel.addButtonBackTo(Client.panelContactDetails,n, n3 += 40, n2, 30); + Panel.addCenterTextTo( + Client.panelContactDetails,n, n3 - 7, "Full name", 1, true); + Client.fullNameInput = Panel.addInputTo(Client.panelContactDetails,n, n3 + 7, n2, 30, 1, 80, false, true); + n3 += 35; + Panel.addButtonBackTo(Client.panelContactDetails,n, n3, n2, 30); + Panel.addCenterTextTo( + Client.panelContactDetails,n, n3 - 7, "Postcode/Zipcode", 1, true); + Client.zipCodeInput = Panel.addInputTo(Client.panelContactDetails,n, n3 + 7, n2, 30, 1, 80, false, true); + n3 += 35; + Panel.addButtonBackTo(Client.panelContactDetails,n, n3, n2, 30); + Panel.addCenterTextTo( + Client.panelContactDetails,n, n3 - 7, "Country", 1, true); + Client.countryInput = Panel.addInputTo(Client.panelContactDetails,n, n3 + 7, n2, 30, 1, 80, false, true); + n3 += 35; + Panel.addButtonBackTo(Client.panelContactDetails,n, n3, n2, 30); + Panel.addCenterTextTo( + Client.panelContactDetails,n, n3 - 7, "Email address", 1, true); + Client.emailInput = Panel.addInputTo(Client.panelContactDetails,n, n3 + 7, n2, 30, 1, 80, false, true); + n3 += 35; + Panel.addButtonBackTo(Client.panelContactDetails,n, n3, 100, 30); + Panel.addCenterTextTo( + Client.panelContactDetails,n, n3, "Submit", 4, true); + Client.chooseSubmitContactDetailsButton = Panel.addButtonTo(Client.panelContactDetails,n, n3, 100, 30); + Panel.setFocus(Client.panelContactDetails,Client.fullNameInput); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static int options_security_hook(int xPos, int yPos, int mouseX, int mouseY) { + short uiWidth = 196; + int currYPos = yPos; + if (Settings.SHOW_ACCOUNT_SECURITY_SETTINGS.get(Settings.currentProfile)) { + currYPos += 5; + Renderer.drawString("Security settings", xPos, currYPos, 1, 0); + currYPos += 15; + int textColor = 16777215; + if (mouseX > xPos + && mouseX < xPos + uiWidth + && mouseY > currYPos - 12 + && mouseY < currYPos + 4) { + textColor = 16776960; + } + Renderer.drawString("Change password", xPos, currYPos, 1, textColor); + currYPos += 15; + textColor = 16777215; + if (mouseX > xPos + && mouseX < xPos + uiWidth + && mouseY > currYPos - 12 + && mouseY < currYPos + 4) { + textColor = 16776960; + } + Renderer.drawString("Change recovery questions", xPos, currYPos, 1, textColor); + currYPos += 15; + textColor = 16777215; + if (mouseX > xPos + && mouseX < xPos + uiWidth + && mouseY > currYPos - 12 + && mouseY < currYPos + 4) { + textColor = 16776960; + } + Renderer.drawString("Change contact details", xPos, currYPos, 1, textColor); + currYPos += 15; + // currYPos += 5; //originally had this extra space but makes moves privacy settings and + // subsequent block + // a bit down with respect to when SHOW_ACCOUNT_SECURITY_SETTINGS is not enabled + } + return currYPos - yPos; + } + + public static int options_security_click_hook( + int xPos, int yPos, int mouseX, int mouseY, int mouseButtonClick) { + short uiWidth = 196; + int currYPos = yPos; + if (Settings.SHOW_ACCOUNT_SECURITY_SETTINGS.get(Settings.currentProfile)) { + currYPos += 15; + currYPos += 20; + if (mouseX > xPos + && mouseX < xPos + uiWidth + && mouseY > currYPos - 12 + && mouseY < currYPos + 4 + && mouseButtonClick == 1) { + AccountManagement.panelPasswordChangeMode = 6; + Client.modal_enteredText = ""; + Client.modal_text = ""; + } + currYPos += 15; + if (mouseX > xPos + && mouseX < xPos + uiWidth + && mouseY > currYPos - 12 + && mouseY < currYPos + 4 + && mouseButtonClick == 1) { + StreamUtil.newPacket(197); + StreamUtil.sendPacket(); + } + currYPos += 15; + if (mouseX > xPos + && mouseX < xPos + uiWidth + && mouseY > currYPos - 12 + && mouseY < currYPos + 4 + && mouseButtonClick == 1) { + StreamUtil.newPacket(247); + StreamUtil.sendPacket(); + } + currYPos += 15; + currYPos += + 30; // originally was += 35 but with the skip tutorial added, clicking logout doesn't do + // it as + // well with the 5 extra spaces. + } + return currYPos - yPos; + } + + public static void draw_change_pass_hook(int mouseX, int mouseY, int mouseButtonClick) { + if (mouseButtonClick != 0) { + mouseButtonClick = 0; + if (mouseX < 106 || mouseY < 150 || mouseX > 406 || mouseY > 210) { + panelPasswordChangeMode = 0; + return; + } + } + + short var1 = 150; + Renderer.drawBox(106, var1, 300, 60, 0); + Renderer.drawBoxBorder(106, var1, 300, 60, 16777215); + int var4 = var1 + 22; + String var2; + int var3; + if (panelPasswordChangeMode == 6) { + Renderer.drawStringCenter("Please enter your current password", 256, var4, 4, 16777215); + var4 += 25; + var2 = "*"; + + for (var3 = 0; var3 < Client.modal_enteredText.length(); ++var3) { + var2 = "X" + var2; + } + + Renderer.drawStringCenter(var2, 256, var4, 4, 16777215); + if (Client.modal_text.length() > 0) { + oldPassword = Client.modal_text; + Client.modal_enteredText = ""; + Client.modal_text = ""; + panelPasswordChangeMode = 1; + return; + } + } else if (panelPasswordChangeMode == 1) { + Renderer.drawStringCenter("Please enter your new password", 256, var4, 4, 16777215); + var4 += 25; + var2 = "*"; + + for (var3 = 0; var3 < Client.modal_enteredText.length(); ++var3) { + var2 = "X" + var2; + } + + Renderer.drawStringCenter(var2, 256, var4, 4, 16777215); + if (Client.modal_text.length() > 0) { + newPassword = Client.modal_text; + Client.modal_enteredText = ""; + Client.modal_text = ""; + panelPasswordChangeMode = 2; + if (newPassword.length() < 5) { + panelPasswordChangeMode = 5; + return; + } + if (newPassword.trim().equalsIgnoreCase(Panel.getControlText(Client.panelLogin, Client.loginUserInput).trim())) { + panelPasswordChangeMode = 7; + return; + } + return; + } + } else if (panelPasswordChangeMode == 2) { + Renderer.drawStringCenter("Enter password again to confirm", 256, var4, 4, 16777215); + var4 += 25; + var2 = "*"; + + for (var3 = 0; var3 < Client.modal_enteredText.length(); ++var3) { + var2 = "X" + var2; + } + + Renderer.drawStringCenter(var2, 256, var4, 4, 16777215); + if (Client.modal_text.length() > 0) { + if (Client.modal_text.equalsIgnoreCase(newPassword)) { + panelPasswordChangeMode = 4; + sendPassChange(oldPassword, newPassword); + return; + } + + panelPasswordChangeMode = 3; + return; + } + } else { + if (panelPasswordChangeMode == 3) { + Renderer.drawStringCenter("Passwords do not match!", 256, var4, 4, 16777215); + var4 += 25; + Renderer.drawStringCenter("Press any key to close", 256, var4, 4, 16777215); + return; + } + + if (panelPasswordChangeMode == 4) { + Renderer.drawStringCenter("Ok, your request has been sent", 256, var4, 4, 16777215); + var4 += 25; + Renderer.drawStringCenter("Press any key to close", 256, var4, 4, 16777215); + return; + } + + if (panelPasswordChangeMode == 5) { + Renderer.drawStringCenter("Password must be at", 256, var4, 4, 16777215); + var4 += 25; + Renderer.drawStringCenter("least 5 letters long", 256, var4, 4, 16777215); + return; + } + + if (panelPasswordChangeMode == 7) { + Renderer.drawStringCenter("Your password must not be", 256, var4, 4, 16777215); + var4 += 25; + Renderer.drawStringCenter("the same as your username", 256, var4, 4, 16777215); + return; + } + } + } + + public static void processForgotPassword() { + if (Settings.SHOW_ACCOUNT_SECURITY_SETTINGS.get(Settings.currentProfile)) { + if (Panel.isSelected(Client.panelLogin, Client.loginLostPasswordButton)) { + String user = Panel.getControlText(Client.panelLogin, Client.loginUserInput); + if (user.trim().length() == 0) { + Client.setLoginMessage("", "You must enter your username to recover your password"); + return; + } + + Client.username_login = user; + forgotPass(user); + } + } + + } // § SECTION hook key and mouse consumption § + /* + * Intercept the part of checking if other panels should consume key event in game, + * we may have logged in flag distinct than 0, but is already checked after this hook, + * so 0 is returned to continue on that flow + * Password change states 3, 4, 5 any 7 are final, so they are changed to 0 and a non-zero + * response is given to break out of trying to consume key on other panels + * For any other non-zero password change state, non-zero response given + */ + public static int ingame_keyhandler_hook(int loggedIn, int key) { + if (loggedIn != 1) return 0; + + if (Client.showRecoveryQuestions) { + if (customQuestionEntry != -1) return 1; + Panel.handleKey(Client.panelRecoveryQuestions, key); + return 1; + } + + if (Client.showContactDetails) { + Panel.handleKey(Client.panelContactDetails, key); + return 1; + } + + if (panelPasswordChangeMode == 3 || panelPasswordChangeMode == 4 || panelPasswordChangeMode == 5 || panelPasswordChangeMode == 7) { + panelPasswordChangeMode = 0; + return 1; + } + + return panelPasswordChangeMode > 0 ? 1 : 0; + } + public static void account_panels_key_hook(int a, int key) { try { if (Client.login_screen == Client.SCREEN_REGISTER_NEW_ACCOUNT) { Panel.handleKey(Client.panelRegister, key); } + + if (Client.login_screen == Client.SCREEN_PASSWORD_RECOVERY) { + Panel.handleKey(Client.panelRecovery, key); + } } catch (Exception e) { e.printStackTrace(); } } - public static void account_panels_input_hook(int n1, int mouseY, int a, int n3, int mouseX) { + public static void account_panels_input_hook(int n1, int mouseY, int n3, int mouseX) { try { if (Client.login_screen == Client.SCREEN_REGISTER_NEW_ACCOUNT) { Panel.handleMouse(Client.panelRegister, n1, mouseY, n3, mouseX); @@ -328,6 +989,13 @@ public static void account_panels_input_hook(int n1, int mouseY, int a, int n3, "@yel@Your password must be at least 5 letters long"); return; } + + if (Panel.getControlText(Client.panelRegister, Client.choosePasswordInput).trim().equalsIgnoreCase(Panel.getControlText(Client.panelRegister, Client.chooseUserInput).trim())) { + Panel.setControlText( + Client.panelRegister, + Client.controlRegister, "@yel@Your password must not be the same as your username!"); + return; + } if (Panel.isToggle(Client.panelRegister, Client.acceptTermsCheckbox) == 0) { Panel.setControlText( @@ -356,8 +1024,153 @@ public static void account_panels_input_hook(int n1, int mouseY, int a, int n3, return; } } + + if (Client.login_screen == Client.SCREEN_PASSWORD_RECOVERY) { + Panel.handleMouse(Client.panelRecovery, n1, mouseY, n3, mouseX); + if (Panel.isSelected(Client.panelRecovery, Client.chooseSubmitRecoveryButton)) { + String var1 = Panel.getControlText(Client.panelRecovery, Client.recoverNewPassInput); + String var2 = Panel.getControlText(Client.panelRecovery, Client.recoverConfirmPassInput); + if (!var1.equalsIgnoreCase(var2)) { + Client.setLoginMessage("", "@yel@The two new passwords entered are not the same as each other!"); + return; + } + + if (var1.length() < 5) { + Client.setLoginMessage("", "@yel@Your new password must be at least 5 letters long"); + return; + } + + recover(); + } + + if (Panel.isSelected(Client.panelRecovery, Client.chooseCancelRecoveryButton)) { + Client.login_screen = Client.SCREEN_CLICK_TO_LOGIN; + } + } } catch (Exception e) { e.printStackTrace(); } } + + public static void recovery_questions_input(int n1, int mouseY, int n3, int mouseX) { + try { + if (customQuestionEntry != -1) { + if (Client.pm_text.length() > 0) { + Client.controlRecoveryText[customQuestionEntry] = Client.pm_text; + Panel.setControlText( + Client.panelRecoveryQuestions,Client.controlRecoveryIns[customQuestionEntry], customQuestionEntry + 1 + ": " + Client.controlRecoveryText[customQuestionEntry]); + Panel.setControlText( + Client.panelRecoveryQuestions,Client.controlAnswerInput[customQuestionEntry], ""); + customQuestionEntry = -1; + } + } else { + Panel.handleMouse(Client.panelRecoveryQuestions, n1, mouseY, n3, mouseX); + + int currSetIdx; + for (int idx = 0; idx < 5; ++idx) { + if (Panel.isSelected(Client.panelRecoveryQuestions, Client.controlQuestion[idx])) { + boolean var2_3 = false; + + while (!var2_3) { + recoveryIndices[idx] = (recoveryIndices[idx] + 1) % recoveryQuestions.length; + var2_3 = true; + + for (currSetIdx = 0; currSetIdx < 5; ++currSetIdx) { + if (currSetIdx != idx && recoveryIndices[currSetIdx] == recoveryIndices[idx]) { + var2_3 = false; + } + } + } + + Client.controlRecoveryText[idx] = recoveryQuestions[recoveryIndices[idx]]; + Panel.setControlText(Client.panelRecoveryQuestions,Client.controlRecoveryIns[idx], idx + 1 + ": " + recoveryQuestions[recoveryIndices[idx]]); + Panel.setControlText(Client.panelRecoveryQuestions,Client.controlAnswerInput[idx], ""); + } + } + + for (int i = 0; i < 5; ++i) { + if (Panel.isSelected(Client.panelRecoveryQuestions,Client.controlCustomQuestion[i])) { + customQuestionEntry = i; + Client.pm_enteredText = ""; + Client.pm_text = ""; + } + } + + if (Panel.isSelected(Client.panelRecoveryQuestions,Client.chooseFinishSetRecoveryButton)) { + currSetIdx = 0; + + while (true) { + if (currSetIdx >= 5) { + for (int outerIdx = 0; outerIdx < 5; ++outerIdx) { + String var5_7 = Panel.getControlText(Client.panelRecoveryQuestions, Client.controlAnswerInput[outerIdx]); + + for (int innerIdx = 0; innerIdx < outerIdx; ++innerIdx) { + String var7_12 = Panel.getControlText(Client.panelRecoveryQuestions, Client.controlAnswerInput[innerIdx]); + if (var5_7.equalsIgnoreCase(var7_12)) { + Panel.setControlText(Client.panelRecoveryQuestions,Client.controlRecoveryQuestions, "@yel@Each question must have a different answer"); + return; + } + } + } + + sendRecoveryQuestions(); + + for (int i = 0; i < 5; ++i) { + recoveryIndices[i] = i; + Client.controlRecoveryText[i] = recoveryQuestions[recoveryIndices[i]]; + Panel.setControlText(Client.panelRecoveryQuestions,Client.controlAnswerInput[i], ""); + Panel.setControlText(Client.panelRecoveryQuestions,Client.controlRecoveryIns[i], i + 1 + ": " + Client.controlRecoveryText[i]); + } + + Client.clearScreen(); + Client.showRecoveryQuestions = false; + break; + } + + String chkAnswer = Panel.getControlText(Client.panelRecoveryQuestions, Client.controlAnswerInput[currSetIdx]); + if (chkAnswer == null || chkAnswer.length() < 3) { + Panel.setControlText(Client.panelRecoveryQuestions,Client.controlRecoveryQuestions, "@yel@Please provide a longer answer to question: " + (currSetIdx + 1)); + return; + } + + ++currSetIdx; + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void contact_details_input(int n1, int mouseY, int n3, int mouseX) { + try { + Panel.handleMouse(Client.panelContactDetails, n1, mouseY, n3, mouseX); + if (Panel.isSelected(Client.panelContactDetails, Client.fullNameInput)) { + Panel.setFocus(Client.panelContactDetails, Client.zipCodeInput); + } + if (Panel.isSelected(Client.panelContactDetails, Client.zipCodeInput)) { + Panel.setFocus(Client.panelContactDetails, Client.countryInput); + } + if (Panel.isSelected(Client.panelContactDetails, Client.countryInput)) { + Panel.setFocus(Client.panelContactDetails, Client.emailInput); + } + if (Panel.isSelected(Client.panelContactDetails, Client.emailInput)) { + Panel.setFocus(Client.panelContactDetails, Client.fullNameInput); + } + if (!Panel.isSelected(Client.panelContactDetails, Client.chooseSubmitContactDetailsButton)) return; + String name = Panel.getControlText(Client.panelContactDetails, Client.fullNameInput); + String zipcode = Panel.getControlText(Client.panelContactDetails, Client.zipCodeInput); + String country = Panel.getControlText(Client.panelContactDetails, Client.countryInput); + String email = Panel.getControlText(Client.panelContactDetails, Client.emailInput); + if (name != null && name.length() != 0 && zipcode != null && zipcode.length() != 0 && country != null && country.length() != 0 && email != null && email.length() != 0) { + sendContactDetails(name, zipcode, country, email); + Client.clearScreen(); + Client.showContactDetails = false; + return; + } + Panel.setControlText(Client.panelContactDetails, Client.controlContactDetails, "@yel@Please fill in all the requested details"); + } catch (Exception e) { + e.printStackTrace(); + } + } } diff --git a/src/Game/Client.java b/src/Game/Client.java index 98211abc..6e537538 100644 --- a/src/Game/Client.java +++ b/src/Game/Client.java @@ -19,18 +19,6 @@ package Game; import static Replay.game.constants.Game.itemActionMap; - -import Client.JClassPatcher; -import Client.JConfig; -import Client.KeybindSet; -import Client.Launcher; -import Client.Logger; -import Client.NotificationsHandler; -import Client.NotificationsHandler.NotifType; -import Client.Settings; -import Client.Speedrun; -import Client.TwitchIRC; -import Replay.game.constants.Game.ItemAction; import java.applet.Applet; import java.io.BufferedReader; import java.io.BufferedWriter; @@ -52,6 +40,17 @@ import java.util.List; import java.util.Map; import javax.swing.JOptionPane; +import Client.JClassPatcher; +import Client.JConfig; +import Client.KeybindSet; +import Client.Launcher; +import Client.Logger; +import Client.NotificationsHandler; +import Client.NotificationsHandler.NotifType; +import Client.Settings; +import Client.Speedrun; +import Client.TwitchIRC; +import Replay.game.constants.Game.ItemAction; /** * This class prepares the client for login, handles chat messages, and performs player related @@ -185,6 +184,8 @@ public class Client { public static String pm_text; public static String pm_enteredText; public static String lastpm_username = null; + public static String modal_text; + public static String modal_enteredText; public static String mouseText = ""; @@ -310,12 +311,18 @@ public class Client { public static int login_delay; public static String server_address; public static int serverjag_port; + public static int session_id; + public static boolean failedRecovery = false; public static Object panelWelcome; public static Object panelLogin; public static Object panelRegister; + public static Object panelRecovery; + public static Object panelRecoveryQuestions; + public static Object panelContactDetails; public static int loginUserInput; public static int loginPassInput; + public static int loginLostPasswordButton; public static int registerButton; public static int controlRegister; public static int chooseUserInput; @@ -324,6 +331,30 @@ public class Client { public static int acceptTermsCheckbox; public static int chooseSubmitRegisterButton; public static int chooseCancelRegisterButton; + public static int controlRecovery1; + public static int controlRecovery2; + public static int controlRecoveryQuestion[] = new int[5]; + public static int controlRecoveryInput[] = new int[5]; + public static int recoverOldPassInput; + public static int recoverNewPassInput; + public static int recoverConfirmPassInput; + public static int chooseSubmitRecoveryButton; + public static int chooseCancelRecoveryButton; + public static int controlRecoveryQuestions; + public static String controlRecoveryText[] = new String[5]; + public static int controlRecoveryIns[] = new int[5]; + public static int controlAnswerInput[] = new int[5]; + public static int controlQuestion[] = new int[5]; + public static int controlCustomQuestion[] = new int[5]; + public static int chooseFinishSetRecoveryButton; + public static int controlContactDetails; + public static int fullNameInput; + public static int zipCodeInput; + public static int countryInput; + public static int emailInput; + public static int chooseSubmitContactDetailsButton; + public static boolean showRecoveryQuestions; + public static boolean showContactDetails; /** * Iterates through {@link #strings} array and checks if various conditions are met. Used for @@ -516,6 +547,16 @@ public static boolean skipToLogin() { return skipToLogin || Settings.START_LOGINSCREEN.get(Settings.currentProfile); } + /** + * Reference for JClassPatcher and any other required. Indicates if should show account and + * security settings + * + * @return + */ + public static boolean showSecuritySettings() { + return Settings.SHOW_ACCOUNT_SECURITY_SETTINGS.get(Settings.currentProfile); + } + /** * Method that gets called when starting game, normally would go to Welcome screen but if no world * configured (using RSC+ for replay mode) skip directly to login for replays @@ -895,6 +936,55 @@ public static void isLoadingHook(boolean isLoading) { } } } + + /** + * General extra check for new received opcodes + * Send false if has finished processing + * @param opcode - Packet opcode + * @param psize - Packet size + * @return false to indicate no more processing is needed + */ + public static boolean newOpcodeReceivedHook(int opcode, int psize) { + boolean couldNotProcess = true; + + if (AccountManagement.processPacket(opcode, psize)) { + couldNotProcess = false; + } + + return couldNotProcess; + } + + /** + * General in game input hook for new added elements + * return false to indicate continue checking conditions in the original gameInput() method + */ + public static boolean gameInputHook(int n1, int mouseY, int n3, int mouseX) { + boolean continueFlow = true; + + if (Client.showRecoveryQuestions) { + AccountManagement.recovery_questions_input(n1, mouseY, n3, mouseX); + continueFlow = false; + } else if (Client.showContactDetails) { + AccountManagement.contact_details_input(n1, mouseY, n3, mouseX); + continueFlow = false; + } + + return continueFlow; + } + + public static void loginOtherButtonCheckHook() { + AccountManagement.processForgotPassword(); + } + + public static boolean drawGameHook() { + boolean continueFlow = true; + + if (AccountManagement.pending_render()) { + continueFlow = false; + } + + return continueFlow; + } public static void resetLoginMessage() { setLoginMessage("Please enter your username and password", ""); @@ -1373,6 +1463,24 @@ public static void clearScreen() { } catch (Exception e) { } } + + public static void setInterlace(boolean value) { + if (Reflection.interlace == null) return; + + try { + Reflection.interlace.set(Renderer.instance, value); + } catch (Exception e) { + } + } + + public static void drawGraphics() { + if (Reflection.drawGraphics == null) return; + + try { + Reflection.drawGraphics.invoke(Renderer.instance, Renderer.graphicsInstance, 0, 256, 0); + } catch (Exception e) { + } + } public static void preGameDisplay() { if (Reflection.preGameDisplay == null) return; @@ -1479,6 +1587,12 @@ public static void retroFPSHook(Object surfaceInstance) { } } } + + public static void initCreateExtraPanelsHook() { + AccountManagement.create_account_recovery(); + AccountManagement.create_recovery_questions(); + AccountManagement.create_contact_details(); + } public static int attack_menu_hook(int cmpVar) { if (Settings.ATTACK_ALWAYS_LEFT_CLICK.get(Settings.currentProfile) diff --git a/src/Game/Panel.java b/src/Game/Panel.java index d4dbb943..bbe80b5e 100644 --- a/src/Game/Panel.java +++ b/src/Game/Panel.java @@ -31,6 +31,18 @@ public class Panel { public static int control_text_size; public static boolean control_use_alt_color; public static String control_text; + + public static Object createPanel(int maxElements) { + if (Reflection.panel == null) return null; + + Object result = null; + try { + result = Reflection.panel.newInstance(Renderer.instance, maxElements); + } catch (Exception e) { + } + + return result; + } public static void drawPanel(Object panelSource) { if (Reflection.drawPanel == null) return; @@ -173,7 +185,6 @@ public static int addButtonTo(Object panelSource, int xPos, int yPos, int width, public static int addInputTo( Object panelSource, - int n, int xPos, int yPos, int width, @@ -190,7 +201,7 @@ public static int addInputTo( (int) Reflection.addInput.invoke( panelSource, - n - 3845, + 0, capacity, width, isBackground, diff --git a/src/Game/Reflection.java b/src/Game/Reflection.java index 68487fe6..5a340e24 100644 --- a/src/Game/Reflection.java +++ b/src/Game/Reflection.java @@ -18,20 +18,21 @@ */ package Game; -import Client.JClassLoader; -import Client.Launcher; -import Client.Logger; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; +import Client.JClassLoader; +import Client.Launcher; +import Client.Logger; /** Loads and sets fields and methods found in the vanilla RSC jar's classes */ public class Reflection { public static Field gameReference = null; + public static Constructor panel = null; public static Constructor stream = null; public static Constructor buffer = null; @@ -81,9 +82,12 @@ public class Reflection { public static Method itemClick = null; public static Method menuGen = null; public static Method drawBox = null; + public static Method drawBoxBorder = null; public static Method drawString = null; + public static Method drawStringCenter = null; public static Method drawLineHoriz = null; public static Method drawLineVert = null; + public static Method drawSprite = null; public static Method newPacket = null; public static Method putByte = null; @@ -99,6 +103,7 @@ public class Reflection { public static Method flushPacket = null; public static Method initIsaac = null; public static Method readResponse = null; + public static Method readBytes = null; public static Field maxRetriesField = null; public static Field bufferField = null; public static Field bufferOffset = null; @@ -108,7 +113,9 @@ public class Reflection { public static Method getNpc = null; public static Method getPlayer = null; + public static Field interlace = null; public static Method clearScreen = null; + public static Method drawGraphics = null; public static Method preGameDisplay = null; public static Method resetTimings = null; public static Method formatText = null; @@ -130,6 +137,7 @@ public class Reflection { public static Method handleKey = null; // Constructor descriptions + private static final String PANEL = "qa(ua,int)"; private static final String STREAM = "da(java.net.Socket,e) throws java.io.IOException"; private static final String BUFFER = "tb(int)"; @@ -151,10 +159,14 @@ public class Reflection { private static final String MENUGEN = "final void wb.a(int,int,boolean,java.lang.String,java.lang.String)"; private static final String DRAWBOX = "final void ua.a(int,byte,int,int,int,int)"; + private static final String DRAWBOXBORDER = "final void ua.e(int,int,int,int,int,int)"; private static final String DRAWSTRING = "final void ua.a(java.lang.String,int,int,int,boolean,int)"; + private static final String DRAWSTRINGCENTER = + "final void ua.a(int,java.lang.String,int,int,int,int)"; private static final String DRAWLINEHORIZ = "final void ua.b(int,int,int,int,byte)"; private static final String DRAWLINEVERT = "final void ua.b(int,int,int,int,int)"; + private static final String DRAWSPRITE = "final void ua.b(int,int,int,int)"; private static final String NEWPACKET = "final void b.b(int,int)"; private static final String PUTBYTE = "final void tb.c(int,int)"; @@ -171,6 +183,7 @@ public class Reflection { private static final String FLUSHPACKET = "final void b.a(int) throws java.io.IOException"; private static final String INIT_ISAAC = "final void b.a(byte,int[])"; private static final String READ_RESPONSE = "final int da.b(boolean) throws java.io.IOException"; + private static final String READ_BYTES = "final void da.a(byte[],int,int,int) throws java.io.IOException"; private static final String CREATE_SOCKET = "private final java.net.Socket client.a(int,int,java.lang.String) throws java.io.IOException"; @@ -178,6 +191,7 @@ public class Reflection { private static final String GETPLAYER = "private final ta client.d(int,int)"; private static final String CLEARSCREEN = "final void ua.a(boolean)"; + private static final String DRAWGRAPHICS = "final void ua.a(java.awt.Graphics,int,int,int)"; private static final String PREGAME_DISPLAY = "private final void client.k(int)"; private static final String RESET_TIMINGS = "final void e.c(int)"; @@ -289,7 +303,7 @@ public static void Load() { leftMethods.addAll( Arrays.asList( - NEWPACKET, LOSECONNECTION, SENDPACKET, FLUSHPACKET, INIT_ISAAC, READ_RESPONSE)); + NEWPACKET, LOSECONNECTION, SENDPACKET, FLUSHPACKET, INIT_ISAAC, READ_RESPONSE, READ_BYTES)); while (c != null && leftMethods.size() > 0) { methods = c.getDeclaredMethods(); for (Method method : methods) { @@ -331,6 +345,13 @@ public static void Load() { leftMethods.remove(READ_RESPONSE); continue; } + if (leftMethods.contains(READ_BYTES) + && method.toGenericString().equals(READ_BYTES)) { + readBytes = method; + Logger.Info("Found readBytes"); + leftMethods.remove(READ_BYTES); + continue; + } } c = c.getSuperclass(); } @@ -480,6 +501,7 @@ public static void Load() { // Renderer c = classLoader.loadClass("ua"); + interlace = c.getDeclaredField("i"); methods = c.getDeclaredMethods(); for (Method method : methods) { if (method.toGenericString().equals(SETGAMEBOUNDS)) { @@ -490,14 +512,26 @@ public static void Load() { clearScreen = method; Logger.Info("Found clearScreen"); } + if (method.toGenericString().equals(DRAWGRAPHICS)) { + drawGraphics = method; + Logger.Info("Found drawGraphics"); + } if (method.toGenericString().equals(DRAWBOX)) { drawBox = method; Logger.Info("Found drawBox"); } + if (method.toGenericString().equals(DRAWBOXBORDER)) { + drawBoxBorder = method; + Logger.Info("Found drawBoxBorder"); + } if (method.toGenericString().equals(DRAWSTRING)) { drawString = method; Logger.Info("Found drawString"); } + if (method.toGenericString().equals(DRAWSTRINGCENTER)) { + drawStringCenter = method; + Logger.Info("Found drawStringCenter"); + } if (method.toGenericString().equals(DRAWLINEHORIZ)) { drawLineHoriz = method; Logger.Info("Found drawLineHoriz"); @@ -506,6 +540,10 @@ public static void Load() { drawLineVert = method; Logger.Info("Found drawLineVert"); } + if (method.toGenericString().equals(DRAWSPRITE)) { + drawSprite = method; + Logger.Info("Found drawSprite"); + } } // Character @@ -605,6 +643,13 @@ public static void Load() { Logger.Info("Found handleKey"); } } + constructors = c.getDeclaredConstructors(); + for (Constructor constructor : constructors) { + if (constructor.toGenericString().equals(PANEL)) { + panel = constructor; + Logger.Info("Found panel"); + } + } c = classLoader.loadClass("wb"); methods = c.getDeclaredMethods(); @@ -655,9 +700,12 @@ public static void Load() { if (itemClick != null) itemClick.setAccessible(true); if (menuGen != null) menuGen.setAccessible(true); if (drawBox != null) drawBox.setAccessible(true); + if (drawBoxBorder != null) drawBoxBorder.setAccessible(true); if (drawString != null) drawString.setAccessible(true); + if (drawStringCenter != null) drawStringCenter.setAccessible(true); if (drawLineHoriz != null) drawLineHoriz.setAccessible(true); if (drawLineVert != null) drawLineVert.setAccessible(true); + if (drawSprite != null) drawSprite.setAccessible(true); if (stream != null) stream.setAccessible(true); if (newPacket != null) newPacket.setAccessible(true); if (putByte != null) putByte.setAccessible(true); @@ -673,6 +721,7 @@ public static void Load() { if (flushPacket != null) flushPacket.setAccessible(true); if (initIsaac != null) initIsaac.setAccessible(true); if (readResponse != null) readResponse.setAccessible(true); + if (readBytes != null) readBytes.setAccessible(true); if (bufferField != null) bufferField.setAccessible(true); if (bufferOffset != null) bufferOffset.setAccessible(true); if (bufferByteArray != null) bufferByteArray.setAccessible(true); @@ -681,11 +730,14 @@ public static void Load() { if (buffer != null) buffer.setAccessible(true); if (getNpc != null) getNpc.setAccessible(true); if (getPlayer != null) getPlayer.setAccessible(true); + if (interlace != null) interlace.setAccessible(true); if (clearScreen != null) clearScreen.setAccessible(true); + if (drawGraphics != null) drawGraphics.setAccessible(true); if (preGameDisplay != null) preGameDisplay.setAccessible(true); if (resetTimings != null) resetTimings.setAccessible(true); if (formatText != null) formatText.setAccessible(true); if (putRandom != null) putRandom.setAccessible(true); + if (panel != null) panel.setAccessible(true); if (addButtonBack != null) addButtonBack.setAccessible(true); if (addCenterText != null) addCenterText.setAccessible(true); if (addButton != null) addButton.setAccessible(true); diff --git a/src/Game/Renderer.java b/src/Game/Renderer.java index 8c99b726..a263f4a2 100644 --- a/src/Game/Renderer.java +++ b/src/Game/Renderer.java @@ -18,12 +18,6 @@ */ package Game; -import Client.Launcher; -import Client.Logger; -import Client.NotificationsHandler; -import Client.NotificationsHandler.NotifType; -import Client.Settings; -import Client.Util; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Dimension; @@ -50,16 +44,24 @@ import java.util.Iterator; import java.util.List; import javax.imageio.ImageIO; +import Client.Launcher; +import Client.Logger; +import Client.NotificationsHandler; +import Client.NotificationsHandler.NotifType; +import Client.Settings; +import Client.Util; /** Handles rendering overlays and client adjustments based on window size */ public class Renderer { public static Object instance = null; + public static Graphics graphicsInstance = null; public static int width; public static int height; public static int height_client; public static int[] pixels; + public static int sprite_media; public static int fps; public static float alpha_time; @@ -1015,7 +1017,8 @@ public static void present(Graphics g, Image image) { // TODO: This will need to be adjusted when the login screen is resizable Rectangle bounds; if (Client.login_screen == Client.SCREEN_USERNAME_PASSWORD_LOGIN) { - bounds = new Rectangle(512 - 148, 346 - 36, 48, 16); + bounds = new Rectangle(512 - 100, 216, 48, 16); + //bounds = new Rectangle(512 - 148, 346 - 36, 48, 16); } else if (Client.login_screen == Client.SCREEN_CLICK_TO_LOGIN) { bounds = new Rectangle(512 - 140, 288, 48, 16); } else { @@ -1803,6 +1806,51 @@ public static void drawPlayerControlShape(Graphics2D g, int x, int y, int height } } + public static void drawBox(int x, int y, int w, int h, int color) { + if (Reflection.drawBox == null) return; + + try { + Reflection.drawBox.invoke(instance, x, (byte) -127, color, y, h, w); + } catch (Exception e) { + } + } + + public static void drawBoxBorder(int x, int y, int w, int h, int color) { + if (Reflection.drawBoxBorder == null) return; + + try { + Reflection.drawBoxBorder.invoke(instance, x, w, y, 27785, h, color); + } catch (Exception e) { + } + } + + public static void drawString(String text, int x, int y, int font, int color) { + if (Reflection.drawString == null) return; + + try { + Reflection.drawString.invoke(instance, text, x, y, color, false, font); + } catch (Exception e) { + } + } + + public static void drawStringCenter(String text, int x, int y, int font, int color) { + if (Reflection.drawStringCenter == null) return; + + try { + Reflection.drawStringCenter.invoke(instance, x, text, color, 0, font, y); + } catch (Exception e) { + } + } + + public static void drawSprite(int x, int y, int id) { + if (Reflection.drawSprite == null) return; + + try { + Reflection.drawSprite.invoke(instance, -1, id, y, x); + } catch (Exception e) { + } + } + public static void takeScreenshot(boolean quiet) { quietScreenshot = quiet; screenshot = true; diff --git a/src/Game/StreamUtil.java b/src/Game/StreamUtil.java index 1705e42b..1c8ded18 100644 --- a/src/Game/StreamUtil.java +++ b/src/Game/StreamUtil.java @@ -57,6 +57,15 @@ public static void flushPacket() { } } + public static void sendPacket() { + if (Reflection.sendPacket == null) return; + + try { + Reflection.sendPacket.invoke(Client.clientStream, 21294); + } catch (Exception e) { + } + } + public static void initIsaac(int[] keys) { if (Reflection.initIsaac == null) return; @@ -152,6 +161,40 @@ public static int readStream() { return response; } + + public static int readByte() { + if (Reflection.readResponse == null) return -1; + return readStream(); + } + + public static int readShort() { + if (Reflection.readResponse == null) return -1; + int i = readByte(); + int j = readByte(); + return i * 256 + j; + } + + public static int readInt() { + if (Reflection.readResponse == null) return -1; + int i = readShort(); + int j = readShort(); + return i * 65536 + j; + } + + public static void readBytes(byte[] byteArr, int length) { + readBytes(byteArr, 0, length); + } + + public static void readBytes(byte[] byteArr, int offset, int length) { + if (Reflection.readBytes == null) return; + int response = -1; + + try { + Reflection.readBytes.invoke(Client.clientStream, byteArr, length, offset, 123); + } catch (Exception e) { + } + + } public static void putBytesTo(Object buffer, byte[] block, int start, int offset) { if (Reflection.putBytes == null) return;