From 707b930a92f4d1076ca5eaee4e147ebd633d7b18 Mon Sep 17 00:00:00 2001 From: Adog64 Date: Mon, 3 Aug 2026 23:18:14 -0700 Subject: [PATCH 1/6] Added Ceasar cypher encryption/decryption to BetterChat module --- .../systems/modules/misc/BetterChat.java | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java index 1c77e88557..8eefd5fa87 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java @@ -47,6 +47,10 @@ import java.util.regex.PatternSyntaxException; public class BetterChat extends Module { + private final int FIRST_USABLE_ASCII = (int) ' '; // 32 + private final int LAST_USABLE_ASCII = (int) '~'; // 126 + private final int NUM_USABLE_ASCII = LAST_USABLE_ASCII - FIRST_USABLE_ASCII + 1; + private final SettingGroup sgGeneral = settings.getDefaultGroup(); private final SettingGroup sgFilter = settings.createGroup("Filter"); private final SettingGroup sgLongerChat = settings.createGroup("Longer Chat"); @@ -104,6 +108,25 @@ public class BetterChat extends Module { .build() ); + private final Setting encrypt = sgGeneral.add(new BoolSetting.Builder() + .name("encrypt") + .description("Applies an encryption routine to chat messages") + .defaultValue(false) + .build() + ); + + private final Setting cypherOffset = sgFilter.add(new IntSetting.Builder() + .name("cypher-offset") + .description("Ceasar cypher offset used for encrypting messages") + .defaultValue(20) + .min(0) + .sliderMin(0) + .max(NUM_USABLE_ASCII - 1) + .sliderMax(NUM_USABLE_ASCII - 1) + .visible(encrypt::get) + .build() + ); + // Filter private final Setting antiSpam = sgFilter.add(new BoolSetting.Builder() @@ -257,6 +280,10 @@ public BetterChat() { private void onMessageReceive(ReceiveMessageEvent event) { Component message = event.getMessage(); + // Always decrypt messages regardless of whether we are encrypting them + String decryptedMessage = applyDecryption(message.getString()); + message = Component.empty().append(decryptedMessage); + if (filterRegex.get()) { String messageString = message.getString(); for (Pattern pattern : filterRegexList) { @@ -322,6 +349,8 @@ private void onMessageSend(SendMessageEvent event) { return; } + if (encrypt.get()) message = applyEncryption(message); + event.message = message; } @@ -511,6 +540,76 @@ private String applyAnnoy(String message) { return message; } + // Encrypt + + private String applyEncryption(String message) { + int msgLen = message.length(); + int offset = cypherOffset.get(); + StringBuilder modString = new StringBuilder(); + + // Encode offset into message with char for validation + modString.append((char) (FIRST_USABLE_ASCII + offset)); + modString.append(encryptChar('%', offset)); + + for (int i = 0; i < msgLen; ++i) { + char chr = message.charAt(i); + chr = encryptChar(chr, offset); + modString.append(chr); + } + return modString.toString(); + } + + private char encryptChar(char chr, int offset) { + int ascii = (int) chr; + if (ascii > FIRST_USABLE_ASCII && ascii <= LAST_USABLE_ASCII) { + ascii -= FIRST_USABLE_ASCII; + ascii += offset; + ascii %= NUM_USABLE_ASCII; + ascii += FIRST_USABLE_ASCII; + chr = (char) ascii; + } + return chr; + } + + // Decrypt + + private String applyDecryption(String message) { + int msgLen = message.length(); + StringBuilder modString = new StringBuilder(); + int msgStart = message.indexOf("> ") + 2; + + int offset = (int)(message.charAt(msgStart)) - FIRST_USABLE_ASCII; + boolean isEncrypted = decryptChar(message.charAt(msgStart+1), offset) == '%'; + + if (isEncrypted) { + for (int i = 0; i < msgLen; ++i) { + char chr = message.charAt(i); + if (i >= msgStart + 2) { + chr = decryptChar(chr, offset); + } + else if (i >= msgStart) { + continue; + } + modString.append(chr); + } + return modString.toString(); + } + return message; + } + + private char decryptChar(char chr, int offset) { + int ascii = (int) chr; + if (ascii > FIRST_USABLE_ASCII && ascii <= LAST_USABLE_ASCII) { + ascii -= FIRST_USABLE_ASCII; + ascii -= offset; + ascii += NUM_USABLE_ASCII; + ascii %= NUM_USABLE_ASCII; + ascii += FIRST_USABLE_ASCII; + chr = (char) ascii; + } + return chr; + } + // Fancy private String applyFancy(String message) { From 8a06aee675ed5b8d2190f82bc6dda46637f8e00e Mon Sep 17 00:00:00 2001 From: Adog64 <33038791+Adog64@users.noreply.github.com> Date: Tue, 4 Aug 2026 17:52:20 -0700 Subject: [PATCH 2/6] Use range instead of min/max Co-authored-by: Crosby <32882447+crosby-moe@users.noreply.github.com> --- .../meteorclient/systems/modules/misc/BetterChat.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java index 8eefd5fa87..51aa8995e1 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java @@ -119,10 +119,8 @@ public class BetterChat extends Module { .name("cypher-offset") .description("Ceasar cypher offset used for encrypting messages") .defaultValue(20) - .min(0) - .sliderMin(0) - .max(NUM_USABLE_ASCII - 1) - .sliderMax(NUM_USABLE_ASCII - 1) + .range(0, NUM_USABLE_ASCII - 1) + .sliderRange(0, NUM_USABLE_ASCII - 1) .visible(encrypt::get) .build() ); From 405665a22626afeb2c8c194cf572188ab98c1a93 Mon Sep 17 00:00:00 2001 From: Adog64 <33038791+Adog64@users.noreply.github.com> Date: Tue, 4 Aug 2026 18:03:14 -0700 Subject: [PATCH 3/6] Construct encryption modString with length Co-authored-by: Crosby <32882447+crosby-moe@users.noreply.github.com> --- .../meteorclient/systems/modules/misc/BetterChat.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java index 51aa8995e1..c50baa26f8 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java @@ -543,7 +543,7 @@ private String applyAnnoy(String message) { private String applyEncryption(String message) { int msgLen = message.length(); int offset = cypherOffset.get(); - StringBuilder modString = new StringBuilder(); + StringBuilder modString = new StringBuilder(msgLen + 2); // Encode offset into message with char for validation modString.append((char) (FIRST_USABLE_ASCII + offset)); From 9a534b050c452763ab6770cfb9fdcd09a6767b04 Mon Sep 17 00:00:00 2001 From: Adog64 Date: Tue, 4 Aug 2026 22:47:19 -0700 Subject: [PATCH 4/6] Decrypt setting and applyDecryption Optional return --- .../systems/modules/misc/BetterChat.java | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java index c50baa26f8..d4d519f995 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java @@ -115,7 +115,14 @@ public class BetterChat extends Module { .build() ); - private final Setting cypherOffset = sgFilter.add(new IntSetting.Builder() + private final Setting decrypt = sgGeneral.add(new BoolSetting.Builder() + .name("decrypt") + .description("Applies a decryption routine to encrypted chat messages") + .defaultValue(true) + .build() + ); + + private final Setting cypherOffset = sgGeneral.add(new IntSetting.Builder() .name("cypher-offset") .description("Ceasar cypher offset used for encrypting messages") .defaultValue(20) @@ -278,9 +285,12 @@ public BetterChat() { private void onMessageReceive(ReceiveMessageEvent event) { Component message = event.getMessage(); - // Always decrypt messages regardless of whether we are encrypting them - String decryptedMessage = applyDecryption(message.getString()); - message = Component.empty().append(decryptedMessage); + if (decrypt.get()) { + Optional decryptedMessage = applyDecryption(message.getString()); + if (decryptedMessage.isPresent()) { + message = Component.empty().append(decryptedMessage.get()); + } + } if (filterRegex.get()) { String messageString = message.getString(); @@ -571,16 +581,22 @@ private char encryptChar(char chr, int offset) { // Decrypt - private String applyDecryption(String message) { - int msgLen = message.length(); + private Optional applyDecryption(String message) { + int rawMsgLen = message.length(); + int nameTagEnd = message.indexOf("> "); + int msgStart = nameTagEnd + 2; + int msgLen = rawMsgLen - msgStart; StringBuilder modString = new StringBuilder(); - int msgStart = message.indexOf("> ") + 2; + + if (msgLen <= 2) { + return Optional.empty(); + } int offset = (int)(message.charAt(msgStart)) - FIRST_USABLE_ASCII; boolean isEncrypted = decryptChar(message.charAt(msgStart+1), offset) == '%'; if (isEncrypted) { - for (int i = 0; i < msgLen; ++i) { + for (int i = 0; i < rawMsgLen; ++i) { char chr = message.charAt(i); if (i >= msgStart + 2) { chr = decryptChar(chr, offset); @@ -590,9 +606,9 @@ else if (i >= msgStart) { } modString.append(chr); } - return modString.toString(); + return Optional.of(modString.toString()); } - return message; + return Optional.empty(); } private char decryptChar(char chr, int offset) { From ef3ed60a16f16654a6b9ec86a21b0eff516152e8 Mon Sep 17 00:00:00 2001 From: Adog64 Date: Thu, 6 Aug 2026 00:27:10 -0700 Subject: [PATCH 5/6] Bypassing 2b spam filter --- .../systems/modules/misc/BetterChat.java | 81 +++++++++++-------- 1 file changed, 48 insertions(+), 33 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java index d4d519f995..08c4411995 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java @@ -48,8 +48,13 @@ public class BetterChat extends Module { private final int FIRST_USABLE_ASCII = (int) ' '; // 32 - private final int LAST_USABLE_ASCII = (int) '~'; // 126 + private final int LAST_USABLE_ASCII = (int) '}'; // 125 private final int NUM_USABLE_ASCII = LAST_USABLE_ASCII - FIRST_USABLE_ASCII + 1; + private final int FIRST_LOWERCASE = (int) 'a'; + private final int LAST_LOWERCASE = (int) 'z'; + private final int FIRST_CAPITAL = (int) 'A'; + private final int LAST_CAPITAL = (int) 'Z'; + private final int NUM_LETTERS = 26; private final SettingGroup sgGeneral = settings.getDefaultGroup(); private final SettingGroup sgFilter = settings.createGroup("Filter"); @@ -122,16 +127,6 @@ public class BetterChat extends Module { .build() ); - private final Setting cypherOffset = sgGeneral.add(new IntSetting.Builder() - .name("cypher-offset") - .description("Ceasar cypher offset used for encrypting messages") - .defaultValue(20) - .range(0, NUM_USABLE_ASCII - 1) - .sliderRange(0, NUM_USABLE_ASCII - 1) - .visible(encrypt::get) - .build() - ); - // Filter private final Setting antiSpam = sgFilter.add(new BoolSetting.Builder() @@ -339,6 +334,8 @@ private void onMessageReceive(ReceiveMessageEvent event) { private void onMessageSend(SendMessageEvent event) { String message = event.message; + if (encrypt.get()) message = applyEncryption(message); + if (annoy.get()) message = applyAnnoy(message); if (fancy.get()) message = applyFancy(message); @@ -357,8 +354,6 @@ private void onMessageSend(SendMessageEvent event) { return; } - if (encrypt.get()) message = applyEncryption(message); - event.message = message; } @@ -552,28 +547,39 @@ private String applyAnnoy(String message) { private String applyEncryption(String message) { int msgLen = message.length(); - int offset = cypherOffset.get(); + int offset = Utils.random(0, 26); //cypherOffset.get(); StringBuilder modString = new StringBuilder(msgLen + 2); // Encode offset into message with char for validation - modString.append((char) (FIRST_USABLE_ASCII + offset)); - modString.append(encryptChar('%', offset)); + modString.append('['); + modString.append((char) (FIRST_CAPITAL + offset)); + modString.append(encryptChar('E', offset)); for (int i = 0; i < msgLen; ++i) { char chr = message.charAt(i); chr = encryptChar(chr, offset); modString.append(chr); } + modString.append(']'); return modString.toString(); } private char encryptChar(char chr, int offset) { int ascii = (int) chr; - if (ascii > FIRST_USABLE_ASCII && ascii <= LAST_USABLE_ASCII) { - ascii -= FIRST_USABLE_ASCII; + if (Character.isUpperCase(chr)) { + ascii -= FIRST_CAPITAL; + ascii += offset; + ascii += NUM_LETTERS; + ascii %= NUM_LETTERS; + ascii += FIRST_CAPITAL; + chr = (char) ascii; + } + else if (Character.isLowerCase(chr)) { + ascii -= FIRST_LOWERCASE; ascii += offset; - ascii %= NUM_USABLE_ASCII; - ascii += FIRST_USABLE_ASCII; + ascii += NUM_LETTERS; + ascii %= NUM_LETTERS; + ascii += FIRST_LOWERCASE; chr = (char) ascii; } return chr; @@ -583,25 +589,26 @@ private char encryptChar(char chr, int offset) { private Optional applyDecryption(String message) { int rawMsgLen = message.length(); - int nameTagEnd = message.indexOf("> "); - int msgStart = nameTagEnd + 2; - int msgLen = rawMsgLen - msgStart; + int nameTagEnd = message.indexOf("> ") + 2; + int encStart = message.indexOf('[') + 1; + int encEnd = message.lastIndexOf(']') - 1; + int msgLen = encEnd - encStart; StringBuilder modString = new StringBuilder(); - if (msgLen <= 2) { + if (msgLen < 2) { return Optional.empty(); } - int offset = (int)(message.charAt(msgStart)) - FIRST_USABLE_ASCII; - boolean isEncrypted = decryptChar(message.charAt(msgStart+1), offset) == '%'; + int offset = (int)(message.charAt(encStart)) - FIRST_CAPITAL; + boolean isEncrypted = decryptChar(message.charAt(encStart+1), offset) == 'E'; if (isEncrypted) { for (int i = 0; i < rawMsgLen; ++i) { char chr = message.charAt(i); - if (i >= msgStart + 2) { + if (i >= encStart+2 && i <= encEnd) { chr = decryptChar(chr, offset); } - else if (i >= msgStart) { + else if (i >= nameTagEnd) { continue; } modString.append(chr); @@ -613,12 +620,20 @@ else if (i >= msgStart) { private char decryptChar(char chr, int offset) { int ascii = (int) chr; - if (ascii > FIRST_USABLE_ASCII && ascii <= LAST_USABLE_ASCII) { - ascii -= FIRST_USABLE_ASCII; + if (Character.isUpperCase(chr)) { + ascii -= FIRST_CAPITAL; + ascii -= offset; + ascii += NUM_LETTERS; + ascii %= NUM_LETTERS; + ascii += FIRST_CAPITAL; + chr = (char) ascii; + } + else if (Character.isLowerCase(chr)) { + ascii -= FIRST_LOWERCASE; ascii -= offset; - ascii += NUM_USABLE_ASCII; - ascii %= NUM_USABLE_ASCII; - ascii += FIRST_USABLE_ASCII; + ascii += NUM_LETTERS; + ascii %= NUM_LETTERS; + ascii += FIRST_LOWERCASE; chr = (char) ascii; } return chr; From 17110d518a2713b5159f903861bfaefa9bbc3d64 Mon Sep 17 00:00:00 2001 From: Adog64 Date: Sat, 8 Aug 2026 16:00:38 -0700 Subject: [PATCH 6/6] Better edge case handling --- .../meteorclient/systems/modules/misc/BetterChat.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java index 08c4411995..f759a921ab 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java @@ -595,7 +595,8 @@ private Optional applyDecryption(String message) { int msgLen = encEnd - encStart; StringBuilder modString = new StringBuilder(); - if (msgLen < 2) { + // Exit early if there is definitely not an encrypted substring + if (msgLen < 2 || encStart == 0 || encEnd == -2 || nameTagEnd == 1) { return Optional.empty(); }