From 71927e060a0692a013afcca52766c6da9f9d8a4e Mon Sep 17 00:00:00 2001 From: amyavi <144570677+amyavi@users.noreply.github.com> Date: Tue, 21 Jan 2025 03:00:26 -0300 Subject: [PATCH 1/2] refactor: use custom ComponentRenderer for custom chat --- .../commands/CustomChatCommand.java | 2 +- .../commands/ReloadConfigCommand.java | 3 - .../config/ChipmunkModMigrations.java | 2 + .../config/migrations/MigrationV1.java | 66 +++++++++++++ .../mixin/ClientPlayNetworkHandlerMixin.java | 2 +- .../chipmunkmod/modules/ChomeNSAuth.java | 1 + .../modules/{ => custom_chat}/CustomChat.java | 63 ++++-------- .../CustomChatComponentRenderer.java | 95 +++++++++++++++++++ .../custom_chat/CustomChatContext.java | 8 ++ .../util/BotValidationUtilities.java | 2 +- .../configurate/ConfigurateUtilities.java | 13 +++ src/main/resources/chipmunkmod.mixins.json | 1 - 12 files changed, 204 insertions(+), 54 deletions(-) create mode 100644 src/main/java/land/chipmunk/chipmunkmod/config/migrations/MigrationV1.java rename src/main/java/land/chipmunk/chipmunkmod/modules/{ => custom_chat}/CustomChat.java (63%) create mode 100644 src/main/java/land/chipmunk/chipmunkmod/modules/custom_chat/CustomChatComponentRenderer.java create mode 100644 src/main/java/land/chipmunk/chipmunkmod/modules/custom_chat/CustomChatContext.java diff --git a/src/main/java/land/chipmunk/chipmunkmod/commands/CustomChatCommand.java b/src/main/java/land/chipmunk/chipmunkmod/commands/CustomChatCommand.java index bb1696c..c861df1 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/commands/CustomChatCommand.java +++ b/src/main/java/land/chipmunk/chipmunkmod/commands/CustomChatCommand.java @@ -3,7 +3,7 @@ package land.chipmunk.chipmunkmod.commands; import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.context.CommandContext; -import land.chipmunk.chipmunkmod.modules.CustomChat; +import land.chipmunk.chipmunkmod.modules.custom_chat.CustomChat; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.minecraft.text.Text; diff --git a/src/main/java/land/chipmunk/chipmunkmod/commands/ReloadConfigCommand.java b/src/main/java/land/chipmunk/chipmunkmod/commands/ReloadConfigCommand.java index 55d1486..ee1caba 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/commands/ReloadConfigCommand.java +++ b/src/main/java/land/chipmunk/chipmunkmod/commands/ReloadConfigCommand.java @@ -5,7 +5,6 @@ import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.context.CommandContext; import land.chipmunk.chipmunkmod.ChipmunkMod; import land.chipmunk.chipmunkmod.modules.CommandCore; -import land.chipmunk.chipmunkmod.modules.CustomChat; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.minecraft.text.Text; @@ -26,8 +25,6 @@ public class ReloadConfigCommand { try { ChipmunkMod.CONFIG = ChipmunkMod.loadConfig(); - - CustomChat.INSTANCE.reloadFormat(); CommandCore.INSTANCE.reloadRelativeArea(); source.sendFeedback(Text.literal("Successfully reloaded the config")); diff --git a/src/main/java/land/chipmunk/chipmunkmod/config/ChipmunkModMigrations.java b/src/main/java/land/chipmunk/chipmunkmod/config/ChipmunkModMigrations.java index 44dbb50..2e7bc86 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/config/ChipmunkModMigrations.java +++ b/src/main/java/land/chipmunk/chipmunkmod/config/ChipmunkModMigrations.java @@ -2,11 +2,13 @@ package land.chipmunk.chipmunkmod.config; import land.chipmunk.chipmunkmod.config.migration.AbstractMigrationManager; import land.chipmunk.chipmunkmod.config.migrations.MigrationV0; +import land.chipmunk.chipmunkmod.config.migrations.MigrationV1; public final class ChipmunkModMigrations extends AbstractMigrationManager { public ChipmunkModMigrations() { super("version"); this.register(new MigrationV0()); // unversioned -> v0 + this.register(new MigrationV1()); } } diff --git a/src/main/java/land/chipmunk/chipmunkmod/config/migrations/MigrationV1.java b/src/main/java/land/chipmunk/chipmunkmod/config/migrations/MigrationV1.java new file mode 100644 index 0000000..c410194 --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkmod/config/migrations/MigrationV1.java @@ -0,0 +1,66 @@ +package land.chipmunk.chipmunkmod.config.migrations; + +import land.chipmunk.chipmunkmod.config.migration.ConfigMigration; +import land.chipmunk.chipmunkmod.util.configurate.ConfigurateUtilities; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.SelectorComponent; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.renderer.TranslatableComponentRenderer; +import org.jetbrains.annotations.NotNull; +import org.spongepowered.configurate.transformation.ConfigurationTransformation; + +import java.util.List; + +import static org.spongepowered.configurate.NodePath.path; + +public final class MigrationV1 implements ConfigMigration { + @Override + public int version() { + return 1; + } + + @Override + public ConfigurationTransformation create() { + return ConfigurationTransformation.builder() + .addAction(path("customChat", "format"), + ConfigurateUtilities.componentTransformer(new CustomChatFormatMigrator(), null)) + .build(); + } + + private static final class CustomChatFormatMigrator extends TranslatableComponentRenderer { + @Override + protected @NotNull Component renderSelector(final @NotNull SelectorComponent component, + final @NotNull Void context) { + final String pattern = component.pattern(); + if (pattern.equals("USERNAME") || pattern.equals("UUID")) { + final SelectorComponent.Builder builder = Component.selector() + .pattern("@s"); + + return this.mergeStyleAndOptionallyDeepRender(component, builder, context); + } + + return super.renderSelector(component, context); + } + + // Older configs had things like: `{ "text": "", "extra": ["MESSAGE"] }` + // We don't need that anymore, transform it to `{ "text": "MESSAGE" }` + @Override + protected @NotNull Component renderText(@NotNull TextComponent component, @NotNull Void context) { + if (!component.content().isEmpty() || component.children().size() != 1) { + return super.renderText(component, context); + } + + final Component onlyChild = component.children().getFirst(); + if (!onlyChild.equals(Component.text("MESSAGE"))) { + return super.renderText(component, context); + } + + final Component newComponent = component + .children(List.of()); // Clear children + final TextComponent.Builder builder = Component.text() + .content("MESSAGE"); + + return this.mergeStyleAndOptionallyDeepRender(newComponent, builder, context); + } + } +} diff --git a/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientPlayNetworkHandlerMixin.java b/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientPlayNetworkHandlerMixin.java index 3817bfd..c22d392 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientPlayNetworkHandlerMixin.java @@ -5,6 +5,7 @@ import land.chipmunk.chipmunkmod.command.CommandManager; import land.chipmunk.chipmunkmod.listeners.Listener; import land.chipmunk.chipmunkmod.listeners.ListenerManager; import land.chipmunk.chipmunkmod.modules.*; +import land.chipmunk.chipmunkmod.modules.custom_chat.CustomChat; import net.minecraft.client.MinecraftClient; import net.minecraft.command.CommandRegistryAccess; import net.minecraft.network.encryption.NetworkEncryptionUtils; @@ -15,7 +16,6 @@ import net.minecraft.network.message.MessageSignatureData; import net.minecraft.network.packet.c2s.play.ChatMessageC2SPacket; import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket; import net.minecraft.network.packet.s2c.play.GameMessageS2CPacket; -import net.minecraft.network.packet.s2c.play.PlayerRemoveS2CPacket; import net.minecraft.registry.DynamicRegistryManager; import net.minecraft.resource.featuretoggle.FeatureSet; import net.minecraft.text.PlainTextContent; diff --git a/src/main/java/land/chipmunk/chipmunkmod/modules/ChomeNSAuth.java b/src/main/java/land/chipmunk/chipmunkmod/modules/ChomeNSAuth.java index 3e25f58..da25db0 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/modules/ChomeNSAuth.java +++ b/src/main/java/land/chipmunk/chipmunkmod/modules/ChomeNSAuth.java @@ -4,6 +4,7 @@ import com.google.common.hash.Hashing; import land.chipmunk.chipmunkmod.ChipmunkMod; import land.chipmunk.chipmunkmod.listeners.Listener; import land.chipmunk.chipmunkmod.listeners.ListenerManager; +import land.chipmunk.chipmunkmod.modules.custom_chat.CustomChat; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.minecraft.text.PlainTextContent; diff --git a/src/main/java/land/chipmunk/chipmunkmod/modules/CustomChat.java b/src/main/java/land/chipmunk/chipmunkmod/modules/custom_chat/CustomChat.java similarity index 63% rename from src/main/java/land/chipmunk/chipmunkmod/modules/CustomChat.java rename to src/main/java/land/chipmunk/chipmunkmod/modules/custom_chat/CustomChat.java index 18c1507..aa9ecba 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/modules/CustomChat.java +++ b/src/main/java/land/chipmunk/chipmunkmod/modules/custom_chat/CustomChat.java @@ -1,8 +1,11 @@ -package land.chipmunk.chipmunkmod.modules; +package land.chipmunk.chipmunkmod.modules.custom_chat; import com.google.common.hash.Hashing; import land.chipmunk.chipmunkmod.ChipmunkMod; +import land.chipmunk.chipmunkmod.modules.Chat; +import land.chipmunk.chipmunkmod.modules.CommandCore; +import land.chipmunk.chipmunkmod.modules.KaboomCheck; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextReplacementConfig; import net.kyori.adventure.text.event.ClickEvent; @@ -15,12 +18,15 @@ import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.network.ClientPlayerEntity; import java.nio.charset.StandardCharsets; +import java.util.Map; import java.util.Timer; import java.util.TimerTask; import java.util.regex.Pattern; public class CustomChat { + private static final LegacyComponentSerializer LEGACY = LegacyComponentSerializer.legacyAmpersand(); private static final GsonComponentSerializer GSON = GsonComponentSerializer.gson(); + private static final CustomChatComponentRenderer RENDERER = new CustomChatComponentRenderer(); // https://github.com/kaboomserver/extras/blob/master/src/main/java/pw/kaboom/extras/modules/player/PlayerChat.java#L49C9-L81C26 private static final TextReplacementConfig URL_REPLACEMENT_CONFIG = @@ -71,8 +77,6 @@ public class CustomChat { public CustomChat (MinecraftClient client) { this.client = client; - - reloadFormat(); } public void init () { @@ -108,37 +112,19 @@ public class CustomChat { timer.purge(); } - public void reloadFormat () { - this.format = GSON.serializeToTree(ChipmunkMod.CONFIG.customChat.format).toString(); - } - public void chat (String message) { final ClientPlayerEntity player = client.player; - if (player == null) return; - if (!enabled || !player.hasPermissionLevel(2) || !player.isCreative()) { Chat.sendChatMessage(message, true); return; } + final Component styledMessage = LEGACY.deserialize(message) + .replaceText(URL_REPLACEMENT_CONFIG); + final String username = MinecraftClient.getInstance().getSession().getUsername(); - - final String sanitizedMessage = message - .replace("\\", "\\\\") - .replace("\"", "\\\""); - - final String randomized = String.valueOf(Math.random()); - - final LegacyComponentSerializer serializer = LegacyComponentSerializer.legacyAmpersand(); - - final Component messageWithColors = serializer.deserialize(message); - final Component completeMessage = messageWithColors.replaceText(URL_REPLACEMENT_CONFIG); - - final String stringMessage = GSON.serialize(completeMessage).replace("MESSAGE", randomized); - final String key = ChipmunkMod.CONFIG.bots.chomens.formatKey; - final String hash = key != null ? Hashing.sha256() .hashString(key + total, StandardCharsets.UTF_8) @@ -148,29 +134,12 @@ public class CustomChat { total++; - try { -// final MutablePlayerListEntry entry = Players.INSTANCE.getEntry(client.getNetworkHandler().getProfile().getId()); + final CustomChatContext context = new CustomChatContext(player.getUuidAsString(), styledMessage, + Map.of("MESSAGE", message, "USERNAME", username, "HASH", hash)); + final Component renderedFormat = RENDERER.render(ChipmunkMod.CONFIG.customChat.format, context) + .compact(); + final String json = GSON.serialize(renderedFormat); -// final Component displayNameComponent = entry.displayName().asComponent(); - -// final String prefix = GsonComponentSerializer.gson().serialize(Component.join(JoinConfiguration.separator(Component.empty()), displayNameComponent.children().get(0))); -// final String displayName = GsonComponentSerializer.gson().serialize(Component.join(JoinConfiguration.separator(Component.empty()), displayNameComponent.children().get(1))); - - // TODO: make this code not ohio code.,., - String sanitizedFormat = format -// .replace("\"PREFIX\"", prefix) -// .replace("\"DISPLAYNAME\"", displayName) - .replace("USERNAME", username) - .replace("UUID", player.getUuidAsString()) - .replace("HASH", hash) - .replace("\"extra\":[\"MESSAGE\"]", "\"extra\":[" + stringMessage + "]") - .replace("MESSAGE", sanitizedMessage) - .replace(randomized, "MESSAGE"); // ohio ohio - - CommandCore.INSTANCE.run((KaboomCheck.INSTANCE.isKaboom ? "minecraft:tellraw @a " : "tellraw @a ") + sanitizedFormat); - } catch (Exception e) { - if (client.player == null) return; - client.player.sendMessage(Component.text(e.toString()).color(NamedTextColor.RED)); - } + CommandCore.INSTANCE.run((KaboomCheck.INSTANCE.isKaboom ? "minecraft:tellraw @a " : "tellraw @a ") + json); } } diff --git a/src/main/java/land/chipmunk/chipmunkmod/modules/custom_chat/CustomChatComponentRenderer.java b/src/main/java/land/chipmunk/chipmunkmod/modules/custom_chat/CustomChatComponentRenderer.java new file mode 100644 index 0000000..219d65c --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkmod/modules/custom_chat/CustomChatComponentRenderer.java @@ -0,0 +1,95 @@ +package land.chipmunk.chipmunkmod.modules.custom_chat; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.ComponentBuilder; +import net.kyori.adventure.text.SelectorComponent; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.Style; +import net.kyori.adventure.text.renderer.TranslatableComponentRenderer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.EnumSet; +import java.util.Set; + +// We don't do any translatable rendering here, but extending from that makes it easier to work with. +public final class CustomChatComponentRenderer extends TranslatableComponentRenderer { + // Can't use this from super :( + private static final Set MERGES; + + static { + final Set merges = EnumSet.allOf(Style.Merge.class); + merges.remove(Style.Merge.EVENTS); + MERGES = Collections.unmodifiableSet(merges); + } + + @Override + protected @NotNull Component renderSelector(final @NotNull SelectorComponent component, + final @NotNull CustomChatContext context) { + final String pattern = component.pattern(); + if (pattern.equals("@s")) { + final SelectorComponent.Builder builder = Component.selector() + .pattern(context.uuid()); + + return this.mergeStyleAndOptionallyDeepRender(component, builder, context); + } + + return super.renderSelector(component, context); + } + + @Override + protected @NotNull Component renderText(final @NotNull TextComponent component, + final @NotNull CustomChatContext context) { + final String content = component.content(); + if (content.equals("MESSAGE")) { + return this.mergeStyle(component, context.message(), context); + } + + final String arg = context.args().get(component.content()); + if (arg != null) { + final TextComponent.Builder builder = Component.text() + .content(arg); + + return this.mergeStyleAndOptionallyDeepRender(component, builder, context); + } + + return super.renderText(component, context); + } + + @SuppressWarnings("NonExtendableApiUsage") // we're not extending it silly + @Override + protected > void mergeStyle(final Component component, final B builder, + final CustomChatContext context) { + super.mergeStyle(component, builder, context); + + // render clickEvent that may contain something like "MESSAGE" + // HoverEvent already handled by super + builder.clickEvent(this.mergeClickEvent(component.clickEvent(), context)); + } + + // super#mergeStyle requires a ComponentBuilder on mergeStyle, this does not + private Component mergeStyle(final Component root, final Component that, final CustomChatContext context) { + final Component result = that.mergeStyle(root, MERGES) + .clickEvent(mergeClickEvent(root.clickEvent(), context)); + + final @Nullable HoverEvent hoverEvent = root.hoverEvent(); + if (hoverEvent != null) { + return result.hoverEvent(hoverEvent.withRenderedValue(this, context)); + } + + return result; + } + + private ClickEvent mergeClickEvent(final ClickEvent clickEvent, final CustomChatContext context) { + if (clickEvent == null) return null; + + final String value = clickEvent.value(); + final String arg = context.args().get(value); + if (arg == null) return clickEvent; + + return ClickEvent.clickEvent(clickEvent.action(), arg); + } +} diff --git a/src/main/java/land/chipmunk/chipmunkmod/modules/custom_chat/CustomChatContext.java b/src/main/java/land/chipmunk/chipmunkmod/modules/custom_chat/CustomChatContext.java new file mode 100644 index 0000000..496db29 --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkmod/modules/custom_chat/CustomChatContext.java @@ -0,0 +1,8 @@ +package land.chipmunk.chipmunkmod.modules.custom_chat; + +import net.kyori.adventure.text.Component; + +import java.util.Map; + +public record CustomChatContext(String uuid, Component message, Map args) { +} diff --git a/src/main/java/land/chipmunk/chipmunkmod/util/BotValidationUtilities.java b/src/main/java/land/chipmunk/chipmunkmod/util/BotValidationUtilities.java index 940b549..d3ba6dc 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/util/BotValidationUtilities.java +++ b/src/main/java/land/chipmunk/chipmunkmod/util/BotValidationUtilities.java @@ -4,7 +4,7 @@ import com.mojang.brigadier.Command; import land.chipmunk.chipmunkmod.ChipmunkMod; import land.chipmunk.chipmunkmod.config.Configuration; import land.chipmunk.chipmunkmod.modules.Chat; -import land.chipmunk.chipmunkmod.modules.CustomChat; +import land.chipmunk.chipmunkmod.modules.custom_chat.CustomChat; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.network.ClientPlayerEntity; diff --git a/src/main/java/land/chipmunk/chipmunkmod/util/configurate/ConfigurateUtilities.java b/src/main/java/land/chipmunk/chipmunkmod/util/configurate/ConfigurateUtilities.java index 793590d..53e4f54 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/util/configurate/ConfigurateUtilities.java +++ b/src/main/java/land/chipmunk/chipmunkmod/util/configurate/ConfigurateUtilities.java @@ -1,12 +1,14 @@ package land.chipmunk.chipmunkmod.util.configurate; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.renderer.ComponentRenderer; import net.minecraft.util.math.BlockBox; import net.minecraft.util.math.BlockPos; import org.spongepowered.configurate.ConfigurationNode; import org.spongepowered.configurate.gson.GsonConfigurationLoader; import org.spongepowered.configurate.serialize.SerializationException; import org.spongepowered.configurate.serialize.TypeSerializerCollection; +import org.spongepowered.configurate.transformation.TransformAction; import java.util.Arrays; @@ -32,4 +34,15 @@ public final class ConfigurateUtilities { return source.node(path); } + + public static TransformAction componentTransformer(final ComponentRenderer renderer, final C ctx) { + return (path, value) -> { + final Component originalComponent = value.get(Component.class); + if (originalComponent == null) return null; + + final Component newComponent = renderer.render(originalComponent, ctx); + value.set(Component.class, newComponent); + return null; + }; + } } diff --git a/src/main/resources/chipmunkmod.mixins.json b/src/main/resources/chipmunkmod.mixins.json index a61592b..56ea828 100644 --- a/src/main/resources/chipmunkmod.mixins.json +++ b/src/main/resources/chipmunkmod.mixins.json @@ -14,7 +14,6 @@ "ElderGuardianAppearanceParticleMixin", "TextMixin", "TextSerializerMixin", - "CommandDispatcherMixin", "SoundSystemMixin", "TextFieldWidgetMixin" ], From c39c65a2cc9da0370294bbd2e3660e516fe48e31 Mon Sep 17 00:00:00 2001 From: amyavi <144570677+amyavi@users.noreply.github.com> Date: Tue, 21 Jan 2025 03:09:36 -0300 Subject: [PATCH 2/2] fix: update default config --- .../java/land/chipmunk/chipmunkmod/config/Configuration.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/land/chipmunk/chipmunkmod/config/Configuration.java b/src/main/java/land/chipmunk/chipmunkmod/config/Configuration.java index aac1d4d..d2da3a8 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/config/Configuration.java +++ b/src/main/java/land/chipmunk/chipmunkmod/config/Configuration.java @@ -81,9 +81,8 @@ public class Configuration { public static class CustomChat { public @NotNull Component format = Component.translatable("chat.type.text", - Component.selector("UUID"), - Component.empty() - .append(Component.text("MESSAGE")) + Component.selector("@s"), + Component.text("MESSAGE") ); } }