From 707b930a92f4d1076ca5eaee4e147ebd633d7b18 Mon Sep 17 00:00:00 2001 From: Adog64 Date: Mon, 3 Aug 2026 23:18:14 -0700 Subject: [PATCH 1/4] 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 1c77e88557b..8eefd5fa87b 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/4] 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 8eefd5fa87b..51aa8995e1c 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/4] 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 51aa8995e1c..c50baa26f8d 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/4] 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 c50baa26f8d..d4d519f9958 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) {