mirror of
https://code.chipmunk.land/ChomeNS/chipmunkmod.git
synced 2025-11-13 18:46:15 +00:00
refactor: use custom ComponentRenderer for custom chat
This commit is contained in:
parent
10645c1cad
commit
71927e060a
12 changed files with 204 additions and 54 deletions
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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"));
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Void> {
|
||||
@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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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<CustomChatContext> {
|
||||
// Can't use this from super :(
|
||||
private static final Set<Style.Merge> MERGES;
|
||||
|
||||
static {
|
||||
final Set<Style.Merge> 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 <B extends ComponentBuilder<?, ?>> 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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<String, String> args) {
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<C> TransformAction componentTransformer(final ComponentRenderer<C> 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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
"ElderGuardianAppearanceParticleMixin",
|
||||
"TextMixin",
|
||||
"TextSerializerMixin",
|
||||
"CommandDispatcherMixin",
|
||||
"SoundSystemMixin",
|
||||
"TextFieldWidgetMixin"
|
||||
],
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue