Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package com.lambda.mixin.network;

import com.lambda.event.EventFlow;
import com.lambda.event.events.ChatEvent;
import com.lambda.event.events.InventoryEvent;
import com.lambda.event.events.WorldEvent;
import com.lambda.interaction.managers.inventory.InventoryManager;
Expand Down Expand Up @@ -118,4 +119,12 @@ private void wrapOnScreenHandlerSlotUpdate(ScreenHandlerSlotUpdateS2CPacket pack
private void wrapOnInventory(InventoryS2CPacket packet, Operation<Void> original) {
InventoryManager.onInventoryUpdate(packet, original);
}

@WrapMethod(method = "sendChatMessage(Ljava/lang/String;)V")
void onSendMessage(String content, Operation<Void> original) {
var event = new ChatEvent.Send(content);

if (!EventFlow.post(event).isCanceled())
original.call(event.getMessage());
}
}
2 changes: 1 addition & 1 deletion src/main/java/com/lambda/mixin/render/ChatHudMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public class ChatHudMixin {

@WrapMethod(method = "addMessage(Lnet/minecraft/text/Text;Lnet/minecraft/network/message/MessageSignatureData;Lnet/minecraft/client/gui/hud/MessageIndicator;)V")
void wrapAddMessage(Text message, MessageSignatureData signatureData, MessageIndicator indicator, Operation<Void> original) {
var event = new ChatEvent.Message(message, signatureData, indicator);
var event = new ChatEvent.Receive(message, signatureData, indicator);

if (!EventFlow.post(event).isCanceled())
original.call(event.getMessage(), event.getSignature(), event.getIndicator());
Expand Down
14 changes: 7 additions & 7 deletions src/main/kotlin/com/lambda/config/groups/FormatterSettings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,22 @@ import com.lambda.util.NamedEnum

class FormatterSettings(
c: Configurable,
baseGroup: NamedEnum,
vararg baseGroup: NamedEnum,
) : FormatterConfig, SettingGroup(c) {
val localeEnum by c.setting("Locale", FormatterConfig.Locales.US, "The regional formatting used for numbers").group(baseGroup).index()
val localeEnum by c.setting("Locale", FormatterConfig.Locales.US, "The regional formatting used for numbers").group(*baseGroup).index()
override val locale get() = localeEnum.locale

val sep by c.setting("Separator", FormatterConfig.TupleSeparator.Comma, "Separator for string serialization of tuple data structures").group(baseGroup).index()
val customSep by c.setting("Custom Separator", "") { sep == FormatterConfig.TupleSeparator.Custom }.group(baseGroup).index()
val sep by c.setting("Separator", FormatterConfig.TupleSeparator.Comma, "Separator for string serialization of tuple data structures").group(*baseGroup).index()
val customSep by c.setting("Custom Separator", "") { sep == FormatterConfig.TupleSeparator.Custom }.group(*baseGroup).index()
override val separator get() = if (sep == FormatterConfig.TupleSeparator.Custom) customSep else sep.separator

val group by c.setting("Tuple Prefix", FormatterConfig.TupleGrouping.Parentheses).group(baseGroup).index()
val group by c.setting("Tuple Prefix", FormatterConfig.TupleGrouping.Parentheses).group(*baseGroup).index()
override val prefix get() = group.prefix
override val postfix get() = group.postfix

val floatingPrecision by c.setting("Floating Precision", 3, 0..6, 1, "Precision for floating point numbers").group(baseGroup).index()
val floatingPrecision by c.setting("Floating Precision", 3, 0..6, 1, "Precision for floating point numbers").group(*baseGroup).index()
override val precision get() = floatingPrecision

val timeFormat by c.setting("Time Format", FormatterConfig.Time.IsoDateTime).group(baseGroup).index()
val timeFormat by c.setting("Time Format", FormatterConfig.Time.IsoDateTime).group(*baseGroup).index()
override val format get() = timeFormat.format
}
4 changes: 3 additions & 1 deletion src/main/kotlin/com/lambda/event/events/ChatEvent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ import net.minecraft.network.message.MessageSignatureData
import net.minecraft.text.Text

sealed class ChatEvent {
class Message(
class Send(var message: String) : Event, Cancellable()

class Receive(
var message: Text,
var signature: MessageSignatureData?,
var indicator: MessageIndicator?,
Expand Down
16 changes: 8 additions & 8 deletions src/main/kotlin/com/lambda/module/modules/chat/AntiSpam.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import com.lambda.util.ChatUtils.slurs
import com.lambda.util.ChatUtils.swears
import com.lambda.util.ChatUtils.toAscii
import com.lambda.util.NamedEnum
import com.lambda.util.text.MessageDirection
import com.lambda.util.text.DirectMessage
import com.lambda.util.text.MessageParser
import com.lambda.util.text.MessageType
import net.minecraft.text.Text
Expand Down Expand Up @@ -79,13 +79,13 @@ object AntiSpam : Module(
}

init {
listen<ChatEvent.Message> { event ->
listen<ChatEvent.Receive> { event ->
var raw = event.message.string
val author = MessageParser.playerName(raw)

if (
ignoreSystem && !MessageType.Both.matches(raw) && !MessageDirection.Both.matches(raw) ||
ignoreDms && MessageDirection.Receive.matches(raw)
ignoreSystem && !MessageType.Both.matches(raw) && !DirectMessage.Both.matches(raw) ||
ignoreDms && DirectMessage.Receive.matches(raw)
) return@listen

val slurMatches = slurs.takeIf { detectSlurs.enabled }.orEmpty().flatMap { it.findAll(raw).toList().reversed() }
Expand All @@ -102,8 +102,8 @@ object AntiSpam : Module(
fun doMatch(replace: ReplaceConfig, matches: Sequence<MatchResult>) {
if (
cancelled ||
filterSystem && !MessageType.Both.matches(raw) && !MessageDirection.Both.matches(raw) ||
filterDms && MessageDirection.Receive.matches(raw) ||
filterSystem && !MessageType.Both.matches(raw) && !DirectMessage.Both.matches(raw) ||
filterDms && DirectMessage.Receive.matches(raw) ||
filterFriends && author?.let { FriendManager.isFriend(it) } == true ||
filterSelf && MessageType.Self.matches(raw)
) return
Expand All @@ -127,9 +127,9 @@ object AntiSpam : Module(
doMatch(detectColors, colorMatches)

if (cancelled) return@listen event.cancel()
if (!hasMatches) return@listen

event.message = Text.of(if (fancyChats) raw.toAscii else raw)
if (hasMatches)
event.message = Text.of(if (fancyChats) raw.toAscii else raw)
}
}

Expand Down
64 changes: 64 additions & 0 deletions src/main/kotlin/com/lambda/module/modules/chat/ChatTimestamp.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2025 Lambda
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.lambda.module.modules.chat

import com.lambda.config.applyEdits
import com.lambda.config.groups.FormatterConfig
import com.lambda.config.groups.FormatterSettings
import com.lambda.event.events.ChatEvent
import com.lambda.event.listener.SafeListener.Companion.listen
import com.lambda.module.Module
import com.lambda.module.tag.ModuleTag
import com.lambda.util.Formatting.format
import com.lambda.util.text.buildText
import com.lambda.util.text.literal
import com.lambda.util.text.styled
import com.lambda.util.text.text
import net.minecraft.util.Formatting
import java.awt.Color
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.ZonedDateTime
import java.time.temporal.ChronoUnit

object ChatTimestamp : Module(
name = "ChatTimestamp",
description = "Displays the time a message was sent next to it",
tag = ModuleTag.CHAT,
) {
var color: Formatting by setting("Color", Formatting.GRAY)
.onValueChange { from, to -> if (to.colorIndex !in 0..15) color = from }

val javaColor: Color get() = Color(color.colorValue!! and 16777215)

val formatter = FormatterSettings(this).apply { applyEdits { hide(::localeEnum, ::sep, ::customSep, ::group, ::floatingPrecision); editTyped(::timeFormat) { defaultValue(FormatterConfig.Time.IsoLocalTime) } } }

private val currentTime get() =
ZonedDateTime.of(LocalDateTime.now(), ZoneId.systemDefault())
.truncatedTo(ChronoUnit.SECONDS)

init {
listen<ChatEvent.Receive> {
it.message = buildText {
text(it.message)
literal(" ")
styled(javaColor, italic = true) { literal(currentTime.format(formatter)) }
}
}
}
}
57 changes: 57 additions & 0 deletions src/main/kotlin/com/lambda/module/modules/chat/CustomChat.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2025 Lambda
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.lambda.module.modules.chat

import com.google.common.collect.Comparators.min
import com.lambda.event.events.ChatEvent
import com.lambda.event.listener.SafeListener.Companion.listen
import com.lambda.module.Module
import com.lambda.module.tag.ModuleTag
import com.lambda.util.NamedEnum

object CustomChat : Module(
name = "CustomChat",
description = "Adds a custom ending to your message",
tag = ModuleTag.CHAT,
) {
private val decoration by setting("Decoration", Decoration.Separator)
private val text by setting("Text", Text.Lambda)

private val customText by setting("Custom Text", "") { text == Text.Custom }

init {
listen<ChatEvent.Send> {
val message = "${it.message} ${decoration.block(text.block())}"
it.message = message.take(min(256, message.length))
}
}

enum class Decoration(val block: (String) -> String) {
Separator({ "| $it" }),
Classic({ "\u00ab $it \u00bb" }),
None({ it })
}

private enum class Text(override val displayName: String, val block: () -> String) : NamedEnum {
Lambda("Lambda", { "ʟᴀᴍʙᴅᴀ" }),
LambdaOnTop("Lambda On Top", { "ʟᴀᴍʙᴅᴀ ᴏɴ ᴛᴏᴘ" }),
KamiBlue("Kami Blue", { "ᴋᴀᴍɪ ʙʟᴜᴇ" }),
LambdaWebsite("Lambda Website", { "lambda-client.org" }),
Custom("Custom", { customText })
}
}
47 changes: 47 additions & 0 deletions src/main/kotlin/com/lambda/module/modules/chat/FancyChat.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright 2025 Lambda
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.lambda.module.modules.chat

import com.lambda.event.events.ChatEvent
import com.lambda.event.listener.SafeListener.Companion.listen
import com.lambda.module.Module
import com.lambda.module.tag.ModuleTag
import com.lambda.util.ChatUtils.toBlue
import com.lambda.util.ChatUtils.toGreen
import com.lambda.util.ChatUtils.toLeet
import com.lambda.util.ChatUtils.toUwu

object FancyChat : Module(
name = "FancyChat",
description = "Makes messages you send - fancy",
tag = ModuleTag.CHAT,
) {
private val uwu by setting("uwu", true)
private val leet by setting("1337", false)
private val green by setting(">", false)
private val blue by setting("`", false)

init {
listen<ChatEvent.Send> {
if (uwu) it.message = it.message.toUwu
if (leet) it.message = it.message.toLeet
if (green) it.message = it.message.toGreen
if (blue) it.message = it.message.toBlue
}
}
}
76 changes: 76 additions & 0 deletions src/main/kotlin/com/lambda/module/modules/chat/FriendHighlight.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright 2025 Lambda
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.lambda.module.modules.chat

import com.lambda.event.events.ChatEvent
import com.lambda.event.listener.SafeListener.Companion.listen
import com.lambda.friend.FriendManager
import com.lambda.module.Module
import com.lambda.module.tag.ModuleTag
import com.lambda.sound.SoundManager.playSound
import com.lambda.util.Communication.logError
import com.lambda.util.text.MessageType
import com.lambda.util.text.buildText
import com.lambda.util.text.literal
import com.lambda.util.text.styled
import net.minecraft.sound.SoundEvents
import net.minecraft.util.Formatting
import java.awt.Color

object FriendHighlight : Module(
name = "FriendHighlight",
description = "Highlights your friends names in chat",
tag = ModuleTag.CHAT,
) {
var color: Formatting by setting("Color", Formatting.GREEN)
.onValueChange { from, to -> if (to.colorIndex !in 0..15) color = from }

val javaColor: Color get() = Color(color.colorValue!! and 16777215)

val bold by setting("Bold", true)
val italic by setting("Italic", false)
val underlined by setting("Underlined", false)
val strikethrough by setting("Strikethrough", false)

val ping by setting("Ping On Message", true)

init {
onEnable {
if (FriendManager.friends.isEmpty())
logError("You don't have any friends added, silly! Go add some friends before using the module")
}

listen<ChatEvent.Receive> {
val raw = it.message.string
val author = MessageType.Others.playerName(raw) ?: return@listen
val content = MessageType.Others.removedOrNull(raw) ?: return@listen

if (!FriendManager.isFriend(author)) return@listen

if (ping) playSound(SoundEvents.ENTITY_EXPERIENCE_ORB_PICKUP)

it.message = buildText {
literal("<")
styled(javaColor, bold, italic, underlined, strikethrough) { literal(author) }
literal(">")

literal(content.toString())
}
}
}
}
Loading