From 20b5917f0302e53a24f9a6bbcd8e3a4d0131311e Mon Sep 17 00:00:00 2001 From: William Date: Tue, 19 Mar 2024 17:19:19 +0000 Subject: [PATCH] feat: add packet-level chat handling support --- build.gradle | 1 - .../william278/huskchat/config/Settings.java | 7 +- velocity/build.gradle | 2 - .../william278/huskchat/VelocityHuskChat.java | 18 +- .../listener/VelocityChatListener.java | 31 +++ .../listener/VelocityEventChatListener.java | 27 +++ .../listener/VelocityPacketChatListener.java | 137 +++++++++++++ ...tener.java => VelocityPlayerListener.java} | 32 +-- .../huskchat/packet/PacketManager.java | 21 -- .../huskchat/packet/PlayerPacketListener.java | 187 ------------------ .../huskchat/packet/RegistryEditor.java | 125 ------------ 11 files changed, 213 insertions(+), 375 deletions(-) create mode 100644 velocity/src/main/java/net/william278/huskchat/listener/VelocityChatListener.java create mode 100644 velocity/src/main/java/net/william278/huskchat/listener/VelocityEventChatListener.java create mode 100644 velocity/src/main/java/net/william278/huskchat/listener/VelocityPacketChatListener.java rename velocity/src/main/java/net/william278/huskchat/listener/{VelocityListener.java => VelocityPlayerListener.java} (60%) delete mode 100644 velocity/src/main/java/net/william278/huskchat/packet/PacketManager.java delete mode 100644 velocity/src/main/java/net/william278/huskchat/packet/PlayerPacketListener.java delete mode 100644 velocity/src/main/java/net/william278/huskchat/packet/RegistryEditor.java diff --git a/build.gradle b/build.gradle index 09ade24..a6d7d99 100644 --- a/build.gradle +++ b/build.gradle @@ -35,7 +35,6 @@ allprojects { mavenLocal() mavenCentral() maven { url = 'https://repo.william278.net/velocity/' } - maven { url = 'https://repo.papermc.io/repository/maven-public/' } maven { url = 'https://repo.codemc.io/repository/maven-releases/' } maven { url = 'https://repo.william278.net/releases/' } maven { url = 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' } diff --git a/common/src/main/java/net/william278/huskchat/config/Settings.java b/common/src/main/java/net/william278/huskchat/config/Settings.java index 1d1ba68..37659a8 100644 --- a/common/src/main/java/net/william278/huskchat/config/Settings.java +++ b/common/src/main/java/net/william278/huskchat/config/Settings.java @@ -60,6 +60,9 @@ public class Settings { @Comment("Whether to automatically check for plugin updates on startup") private boolean checkForUpdates = true; + @Comment("Whether to handle chat packets directly for better 1.19+ support (may cause rare compatibility issues)") + private boolean usePacketListening = true; + @Comment("Placeholder settings") private PlaceholderSettings placeholder = new PlaceholderSettings(); @@ -74,10 +77,6 @@ public static class PlaceholderSettings { private long cacheTime = 3000; } -// todo MOVE -// @Comment("Enabled chat filters") -// private List chatFilters = List.of(); - @Comment("Message comamnd settings") private MessageSettings messageCommand = new MessageSettings(); diff --git a/velocity/build.gradle b/velocity/build.gradle index 7a0d4f7..4c79190 100644 --- a/velocity/build.gradle +++ b/velocity/build.gradle @@ -4,9 +4,7 @@ plugins { dependencies { implementation project(path: ':common') - implementation 'org.bstats:bstats-velocity:3.0.2' - implementation 'com.github.retrooper.packetevents:velocity:2.2.0' compileOnly "com.velocitypowered:velocity-api:${velocity_api_version}-SNAPSHOT" compileOnly "com.velocitypowered:velocity-proxy:${velocity_api_version}-SNAPSHOT" diff --git a/velocity/src/main/java/net/william278/huskchat/VelocityHuskChat.java b/velocity/src/main/java/net/william278/huskchat/VelocityHuskChat.java index 7198e7b..b230856 100644 --- a/velocity/src/main/java/net/william278/huskchat/VelocityHuskChat.java +++ b/velocity/src/main/java/net/william278/huskchat/VelocityHuskChat.java @@ -44,7 +44,9 @@ import net.william278.huskchat.getter.DataGetter; import net.william278.huskchat.getter.DefaultDataGetter; import net.william278.huskchat.getter.LuckPermsDataGetter; -import net.william278.huskchat.packet.PacketManager; +import net.william278.huskchat.listener.VelocityEventChatListener; +import net.william278.huskchat.listener.VelocityPacketChatListener; +import net.william278.huskchat.listener.VelocityPlayerListener; import net.william278.huskchat.placeholders.DefaultReplacer; import net.william278.huskchat.placeholders.PAPIProxyBridgeReplacer; import net.william278.huskchat.placeholders.PlaceholderReplacer; @@ -124,8 +126,12 @@ public void onProxyInitialization(@NotNull ProxyInitializeEvent event) { } // Register events -// getProxyServer().getEventManager().register(this, new VelocityListener(this)); - new PacketManager(this).load(); // todo wip + getProxyServer().getEventManager().register(this, new VelocityPlayerListener(this)); + if (getSettings().isUsePacketListening()) { + new VelocityPacketChatListener(this).register(); + } else { + getProxyServer().getEventManager().register(this, new VelocityEventChatListener(this)); + } // Register commands & channel shortcuts VelocityCommand.Type.registerAll(this); @@ -173,13 +179,15 @@ public Optional getPlayer(@NotNull UUID uuid) { } @Override - public @NotNull Collection getOnlinePlayers() { + @NotNull + public Collection getOnlinePlayers() { return getProxyServer().getAllPlayers().stream() .map(player -> (OnlineUser) VelocityUser.adapt(player, this)).toList(); } @Override - public @NotNull Collection getOnlinePlayersOnServer(@NotNull OnlineUser user) { + @NotNull + public Collection getOnlinePlayersOnServer(@NotNull OnlineUser user) { return ((VelocityUser) user).getPlayer().getCurrentServer() .map(conn -> conn.getServer().getPlayersConnected().stream() .map(player -> (OnlineUser) VelocityUser.adapt(player, this)).toList()) diff --git a/velocity/src/main/java/net/william278/huskchat/listener/VelocityChatListener.java b/velocity/src/main/java/net/william278/huskchat/listener/VelocityChatListener.java new file mode 100644 index 0000000..aef8ca3 --- /dev/null +++ b/velocity/src/main/java/net/william278/huskchat/listener/VelocityChatListener.java @@ -0,0 +1,31 @@ +package net.william278.huskchat.listener; + +import com.velocitypowered.api.event.player.PlayerChatEvent; +import net.william278.huskchat.HuskChat; +import net.william278.huskchat.channel.Channel; +import net.william278.huskchat.message.ChatMessage; +import net.william278.huskchat.user.VelocityUser; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; + +public interface VelocityChatListener { + + default boolean handlePlayerChat(PlayerChatEvent e) { + final VelocityUser player = VelocityUser.adapt(e.getPlayer(), plugin()); + final Optional channel = plugin().getChannels().getChannel( + plugin().getUserCache().getPlayerChannel(player.getUuid()) + ); + if (channel.isEmpty()) { + plugin().getLocales().sendMessage(player, "error_no_channel"); + return false; + } + + // Send the chat message, determine if the event should be canceled + return !new ChatMessage(channel.get(), player, e.getMessage(), plugin()).dispatch(); + } + + @NotNull + HuskChat plugin(); + +} diff --git a/velocity/src/main/java/net/william278/huskchat/listener/VelocityEventChatListener.java b/velocity/src/main/java/net/william278/huskchat/listener/VelocityEventChatListener.java new file mode 100644 index 0000000..d68b42a --- /dev/null +++ b/velocity/src/main/java/net/william278/huskchat/listener/VelocityEventChatListener.java @@ -0,0 +1,27 @@ +package net.william278.huskchat.listener; + +import com.velocitypowered.api.event.PostOrder; +import com.velocitypowered.api.event.Subscribe; +import com.velocitypowered.api.event.player.PlayerChatEvent; +import net.william278.huskchat.HuskChat; +import org.jetbrains.annotations.NotNull; + +public record VelocityEventChatListener(@NotNull HuskChat plugin) implements VelocityChatListener { + + @Subscribe(order = PostOrder.LATE) + public void onPlayerChat(PlayerChatEvent e) { + if (!e.getResult().isAllowed()) { + return; + } + if (!this.handlePlayerChat(e)) { + e.setResult(PlayerChatEvent.ChatResult.denied()); + } + } + + @Override + @NotNull + public HuskChat plugin() { + return plugin; + } + +} diff --git a/velocity/src/main/java/net/william278/huskchat/listener/VelocityPacketChatListener.java b/velocity/src/main/java/net/william278/huskchat/listener/VelocityPacketChatListener.java new file mode 100644 index 0000000..7902014 --- /dev/null +++ b/velocity/src/main/java/net/william278/huskchat/listener/VelocityPacketChatListener.java @@ -0,0 +1,137 @@ +package net.william278.huskchat.listener; + +import com.google.common.collect.Sets; +import com.velocitypowered.api.event.AwaitingEventExecutor; +import com.velocitypowered.api.event.EventTask; +import com.velocitypowered.api.event.connection.DisconnectEvent; +import com.velocitypowered.api.event.connection.PostLoginEvent; +import com.velocitypowered.api.event.player.PlayerChatEvent; +import com.velocitypowered.api.proxy.Player; +import com.velocitypowered.proxy.connection.client.ConnectedPlayer; +import com.velocitypowered.proxy.network.Connections; +import com.velocitypowered.proxy.protocol.packet.chat.keyed.KeyedPlayerChatPacket; +import com.velocitypowered.proxy.protocol.packet.chat.legacy.LegacyChatPacket; +import com.velocitypowered.proxy.protocol.packet.chat.session.SessionPlayerChatPacket; +import io.netty.channel.Channel; +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPromise; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import net.william278.desertwell.util.ThrowingConsumer; +import net.william278.huskchat.HuskChat; +import net.william278.huskchat.VelocityHuskChat; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +public class VelocityPacketChatListener { + private static final String KEY = "huskchat"; + + private final VelocityHuskChat plugin; + @Getter + private final Set huskChatEntries; + + public VelocityPacketChatListener(@NotNull VelocityHuskChat plugin) { + this.plugin = plugin; + this.huskChatEntries = Sets.newConcurrentHashSet(); + } + + public void register() { + this.loadPlayers(); + this.loadListeners(); + } + + private void loadPlayers() { + plugin.getServer().getAllPlayers().forEach(this::injectPlayer); + } + + private void loadListeners() { + plugin.getServer().getEventManager().register(plugin, PostLoginEvent.class, + (AwaitingEventExecutor) postLoginEvent -> EventTask.withContinuation(continuation -> { + injectPlayer(postLoginEvent.getPlayer()); + continuation.resume(); + })); + + plugin.getServer().getEventManager().register(plugin, DisconnectEvent.class, + (AwaitingEventExecutor) disconnectEvent -> + disconnectEvent.getLoginStatus() == DisconnectEvent.LoginStatus.CONFLICTING_LOGIN + ? null + : EventTask.async(() -> removePlayer(disconnectEvent.getPlayer()))); + } + + public void injectPlayer(@NotNull Player player) { + final PlayerChannelHandler handler = new PlayerChannelHandler(plugin, player); + final ConnectedPlayer connectedPlayer = (ConnectedPlayer) player; + removePlayer(player); + connectedPlayer.getConnection() + .getChannel() + .pipeline() + .addBefore(Connections.HANDLER, KEY, handler); + } + + public void removePlayer(@NotNull Player player) { + final ConnectedPlayer connectedPlayer = (ConnectedPlayer) player; + final Channel channel = connectedPlayer.getConnection().getChannel(); + if (channel.pipeline().get(KEY) != null) { + channel.pipeline().remove(KEY); + } + } + + @RequiredArgsConstructor + public static class PlayerChannelHandler extends ChannelDuplexHandler implements VelocityChatListener { + + private final VelocityHuskChat plugin; + private final Player player; + + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + final Optional message = this.extractChatMessage(msg); + if (message.isEmpty()) { + super.write(ctx, msg, promise); + return; + } + this.handleChat(message.get(), (passthrough) -> super.write(ctx, msg, promise)); + } + + @NotNull + private Optional extractChatMessage(Object msg) { + if (msg instanceof final SessionPlayerChatPacket session) { + // Handle session chat (1.19.4+) + return Optional.of(session.getMessage()); + } else if (msg instanceof final KeyedPlayerChatPacket keyed) { + // Handle keyed chat (1.19.2-4) + return Optional.of(keyed.getMessage()); + } else if (msg instanceof final LegacyChatPacket legacy) { + // Handle legacy chat (pre-1.19.1) + return Optional.of(legacy.getMessage()); + } + return Optional.empty(); + } + + private void handleChat(@NotNull String message, @NotNull ThrowingConsumer ifAllowed) { + this.dispatchEvent(message) + .thenApply(event -> event.getResult().isAllowed() && handlePlayerChat(event)) + .thenAccept(allowed -> { + if (allowed) { + ifAllowed.accept(null); + } + }); + } + + @NotNull + private CompletableFuture dispatchEvent(@NotNull String message) { + return plugin.getServer().getEventManager().fire(new PlayerChatEvent(player, message)); + } + + @Override + @NotNull + public HuskChat plugin() { + return plugin; + } + } + +} diff --git a/velocity/src/main/java/net/william278/huskchat/listener/VelocityListener.java b/velocity/src/main/java/net/william278/huskchat/listener/VelocityPlayerListener.java similarity index 60% rename from velocity/src/main/java/net/william278/huskchat/listener/VelocityListener.java rename to velocity/src/main/java/net/william278/huskchat/listener/VelocityPlayerListener.java index 784fd76..ad6da28 100644 --- a/velocity/src/main/java/net/william278/huskchat/listener/VelocityListener.java +++ b/velocity/src/main/java/net/william278/huskchat/listener/VelocityPlayerListener.java @@ -19,48 +19,20 @@ package net.william278.huskchat.listener; -import com.velocitypowered.api.event.PostOrder; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.connection.DisconnectEvent; import com.velocitypowered.api.event.connection.PostLoginEvent; -import com.velocitypowered.api.event.player.PlayerChatEvent; import com.velocitypowered.api.event.player.ServerConnectedEvent; import net.william278.huskchat.HuskChat; -import net.william278.huskchat.channel.Channel; -import net.william278.huskchat.message.ChatMessage; import net.william278.huskchat.user.VelocityUser; import org.jetbrains.annotations.NotNull; -import java.util.Optional; +public class VelocityPlayerListener extends PlayerListener { -public class VelocityListener extends PlayerListener { - - public VelocityListener(@NotNull HuskChat plugin) { + public VelocityPlayerListener(@NotNull HuskChat plugin) { super(plugin); } - @Subscribe(order = PostOrder.LATE) - public void onPlayerChat(PlayerChatEvent e) { - if (!e.getResult().isAllowed()) { - return; - } - - // Verify they are in a channel - final VelocityUser player = VelocityUser.adapt(e.getPlayer(), plugin); - final Optional channel = plugin.getChannels().getChannel( - plugin.getUserCache().getPlayerChannel(player.getUuid()) - ); - if (channel.isEmpty()) { - plugin.getLocales().sendMessage(player, "error_no_channel"); - return; - } - - // Send the chat message, determine if the event should be canceled - if (new ChatMessage(channel.get(), player, e.getMessage(), plugin).dispatch()) { - e.setResult(PlayerChatEvent.ChatResult.denied()); - } - } - @Subscribe public void onPlayerChangeServer(ServerConnectedEvent e) { final String server = e.getServer().getServerInfo().getName(); diff --git a/velocity/src/main/java/net/william278/huskchat/packet/PacketManager.java b/velocity/src/main/java/net/william278/huskchat/packet/PacketManager.java deleted file mode 100644 index 66ac779..0000000 --- a/velocity/src/main/java/net/william278/huskchat/packet/PacketManager.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.william278.huskchat.packet; - -import com.github.retrooper.packetevents.PacketEvents; -import io.github.retrooper.packetevents.velocity.factory.VelocityPacketEventsBuilder; -import net.william278.huskchat.VelocityHuskChat; -import org.jetbrains.annotations.NotNull; - -public class PacketManager { - - private final VelocityHuskChat plugin; - - public PacketManager(@NotNull VelocityHuskChat plugin) { - this.plugin = plugin; - } - - public void load() { - PacketEvents.setAPI(VelocityPacketEventsBuilder.build(plugin.getProxyServer(), plugin.getContainer())); - PacketEvents.getAPI().load(); - PacketEvents.getAPI().getEventManager().registerListener(new PlayerPacketListener(plugin)); - } -} diff --git a/velocity/src/main/java/net/william278/huskchat/packet/PlayerPacketListener.java b/velocity/src/main/java/net/william278/huskchat/packet/PlayerPacketListener.java deleted file mode 100644 index 91b25ca..0000000 --- a/velocity/src/main/java/net/william278/huskchat/packet/PlayerPacketListener.java +++ /dev/null @@ -1,187 +0,0 @@ -package net.william278.huskchat.packet; - -import com.github.retrooper.packetevents.PacketEvents; -import com.github.retrooper.packetevents.event.SimplePacketListenerAbstract; -import com.github.retrooper.packetevents.event.simple.PacketConfigSendEvent; -import com.github.retrooper.packetevents.event.simple.PacketPlayReceiveEvent; -import com.github.retrooper.packetevents.manager.player.PlayerManager; -import com.github.retrooper.packetevents.protocol.chat.ChatTypes; -import com.github.retrooper.packetevents.protocol.chat.LastSeenMessages; -import com.github.retrooper.packetevents.protocol.chat.MessageSignature; -import com.github.retrooper.packetevents.protocol.chat.filter.FilterMask; -import com.github.retrooper.packetevents.protocol.chat.message.ChatMessage_v1_19_1; -import com.github.retrooper.packetevents.protocol.chat.message.ChatMessage_v1_19_3; -import com.github.retrooper.packetevents.protocol.nbt.NBTCompound; -import com.github.retrooper.packetevents.protocol.packettype.PacketType; -import com.github.retrooper.packetevents.protocol.player.User; -import com.github.retrooper.packetevents.util.crypto.MessageSignData; -import com.github.retrooper.packetevents.wrapper.configuration.server.WrapperConfigServerRegistryData; -import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientChatMessage; -import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerChatMessage; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import io.netty.buffer.ByteBuf; -import net.kyori.adventure.text.Component; -import net.william278.huskchat.VelocityHuskChat; -import org.jetbrains.annotations.NotNull; - -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.logging.Level; - -public class PlayerPacketListener extends SimplePacketListenerAbstract { - - private static final int MAX_SEEN = 20; - - private final VelocityHuskChat plugin; - private final PlayerManager playerManager = PacketEvents.getAPI().getPlayerManager(); - private final Map> seenMessages = Maps.newConcurrentMap(); - private final List allMessages = Lists.newArrayList(); - - public PlayerPacketListener(@NotNull VelocityHuskChat plugin) { - this.plugin = plugin; - ChatTypes.define(RegistryEditor.HUSKCHAT.getName().asString()); - } - - @Override - public void onPacketPlayReceive(PacketPlayReceiveEvent event) { - if (event.getPacketType() == PacketType.Play.Client.CHAT_MESSAGE) { - try { - final WrapperPlayClientChatMessage packet = new WrapperPlayClientChatMessage(event); - this.sendSignedMessage(event.getUser(), packet); - event.setCancelled(true); - } catch (Throwable e) { - plugin.log(Level.SEVERE, "Failed to handle CHAT_MESSAGE packet", e); - } - } else if (event.getPacketType() == PacketType.Play.Client.CHAT_ACK) { - try { - final ByteBuf byteBuf = (ByteBuf) event.getByteBuf(); - seenMessages.getOrDefault(event.getUser().getUUID(), Lists.newArrayList()) - .add(allMessages.get(byteBuf.readInt())); - plugin.log(Level.INFO, "Received CHAT_ACK packet"); - event.setCancelled(true); - } catch (Throwable e) { - plugin.log(Level.SEVERE, "Failed to handle CHAT_ACK packet", e); - } - } - } - - @Override - public void onPacketConfigSend(PacketConfigSendEvent event) { - if (event.getPacketType() == PacketType.Configuration.Server.REGISTRY_DATA) { - try { - final WrapperConfigServerRegistryData wrapper = new WrapperConfigServerRegistryData(event); - wrapper.setRegistryData(injectChatTypes(wrapper.getRegistryData())); - event.markForReEncode(true); - - // Initialize the user's message history - final UUID uuid = event.getUser().getUUID(); - seenMessages.put(uuid, Lists.newArrayList()); - } catch (Throwable e) { - plugin.log(Level.SEVERE, "Failed to handle SERVERBOUND_REGISTRY_SYNC packet", e); - } - } - } - - @NotNull - private NBTCompound injectChatTypes(@NotNull NBTCompound data) { - final RegistryEditor wrapper = new RegistryEditor(data); - wrapper.injectTypes(List.of(RegistryEditor.HUSKCHAT)); - return wrapper.root(); - } - - private void sendSignedMessage(@NotNull User sender, @NotNull WrapperPlayClientChatMessage packet) { - if (packet.getLastSeenMessages() == null) { - throw new IllegalStateException("LastSeenMessages is null"); - } - - (plugin.getPlayer(sender.getUUID())).get().sendMessage(Component.text( - "Offset: " + packet.getLastSeenMessages().getOffset() + " " - + packet.getLastSeenMessages().getAcknowledged().toString() - )); - - int messagesSinceILastSentOne = packet.getLastSeenMessages().getOffset(); - int messagesSinceILastSaw = packet.getLastSeenMessages().getAcknowledged().size(); - - // todo isAllowed - try { - plugin.log(Level.INFO, "Sending signed message 1"); - final MessageSignData sign = packet.getMessageSignData().orElse(null); - if (sign == null) { - plugin.log(Level.WARNING, "Failed to send signed message (no sign data)"); - return; - } - plugin.log(Level.INFO, "Sending signed message 2"); - - System.out.println("SENDING: " + UUID.nameUUIDFromBytes(sign.getSaltSignature().getSignature()).toString().split("-")[0]); - - ChatMessage_v1_19_3 message = new ChatMessage_v1_19_3( - sender.getUUID(), - 0, - sign.getSaltSignature().getSignature(), - packet.getMessage(), - sign.getTimestamp(), - sign.getSaltSignature().getSalt(), - null, - null, - FilterMask.PASS_THROUGH, - new ChatMessage_v1_19_1.ChatTypeBoundNetwork( -// ChatTypes.getByName(RegistryEditor.HUSKCHAT.getName().asString()), - ChatTypes.CHAT, - Component.text(sender.getName()), //todo chat message format goes here - null - ) - ); - plugin.log(Level.INFO, "Sending signed message 3"); - final LastMessage thisMessage = new LastMessage(sender.getUUID(), sign.getSaltSignature().getSignature()); - plugin.getProxyServer().getAllPlayers().forEach(receiver -> { - final List seen = seenMessages.getOrDefault(receiver.getUniqueId(), Lists.newArrayList()); - playerManager.sendPacket(receiver, getChatPacket(message, seen)); - seen.add(thisMessage); - }); - allMessages.add(0, thisMessage); - - } catch (Throwable e) { - plugin.log(Level.SEVERE, "Failed to dispatch packet (unsupported client or server version)", e); - } - } - - @NotNull - private WrapperPlayServerChatMessage getChatPacket(@NotNull ChatMessage_v1_19_3 message, @NotNull List seen) { - message.setIndex((int) seen.stream().filter(s -> s.sender.equals(message.getSenderUUID())).count()); - message.setLastSeenMessagesPacked(LastMessage.pack(allMessages, seen)); - return new WrapperPlayServerChatMessage(message); - } - - private record LastMessage(UUID sender, byte[] signature) { - - // Pack the last MAX_SEEN messages into an Array of LastSeenMessages.Packed - @NotNull - private static LastSeenMessages.Packed pack(@NotNull List all, @NotNull List seen) { - final List packed = Lists.newArrayList(); - for (int i = Math.min(all.size() - 1, MAX_SEEN - 1); i >= 0; i--) { - final LastMessage message = all.get(i); - if (packed.isEmpty() && !seen.contains(message)) { - continue; - } - packed.add(seen.contains(message) - ? new MessageSignature.Packed(i) - : new MessageSignature.Packed(new MessageSignature(message.signature))); - System.out.println("SENT: " + UUID.nameUUIDFromBytes(message.signature).toString().split("-")[0]); - } - return new LastSeenMessages.Packed(packed); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof LastMessage message && message.sender.equals(sender)) { - return Arrays.equals(message.signature, signature); - } - return false; - } - - } - -} \ No newline at end of file diff --git a/velocity/src/main/java/net/william278/huskchat/packet/RegistryEditor.java b/velocity/src/main/java/net/william278/huskchat/packet/RegistryEditor.java deleted file mode 100644 index 6ef0c8e..0000000 --- a/velocity/src/main/java/net/william278/huskchat/packet/RegistryEditor.java +++ /dev/null @@ -1,125 +0,0 @@ -package net.william278.huskchat.packet; - -import com.github.retrooper.packetevents.protocol.nbt.*; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import net.kyori.adventure.key.Key; -import org.jetbrains.annotations.NotNull; - -import java.util.List; -import java.util.Locale; -import java.util.Map; - -public record RegistryEditor(NBTCompound root) { - - public static ChatType HUSKCHAT = RegistryEditor.ChatType.builder() - .name(Key.key("huskchat", "format")) - .id(50) - .elements(Map.of( - RegistryEditor.ChatType.ElementType.CHAT, - RegistryEditor.ChatType.ElementData.builder() - .translationKey("%s%s") - .parameters(List.of( - RegistryEditor.ChatType.ElementData.ElementParameter.SENDER, - RegistryEditor.ChatType.ElementData.ElementParameter.CONTENT - )) - .build(), - RegistryEditor.ChatType.ElementType.NARRATION, - RegistryEditor.ChatType.ElementData.builder() - .translationKey("chat.type.text.narrate") - .parameters(List.of( - RegistryEditor.ChatType.ElementData.ElementParameter.SENDER, - RegistryEditor.ChatType.ElementData.ElementParameter.CONTENT - )) - .build() - )) - .build(); - - public void injectTypes(@NotNull List toAdd) { - System.out.println("Adding chat types"); - System.out.println(root.getTags().keySet()); - NBTList values = root - .getCompoundTagOrThrow("minecraft:chat_type") - .getCompoundListTagOrThrow("value"); - for (ChatType chatType : toAdd) { - NBTCompound elements = new NBTCompound(); - for (ChatType.ElementType type : chatType.elements.keySet()) { - elements.setTag(type.id(), chatType.elements.get(type).toTag()); - } - - NBTCompound chatTypeTag = new NBTCompound(); - chatTypeTag.setTag("name", new NBTString(chatType.name.asString())); - chatTypeTag.setTag("id", new NBTInt(chatType.id)); - chatTypeTag.setTag("element", elements); - values.addTag(chatTypeTag); - } - } - - @Getter - @Builder - @AllArgsConstructor - public static class ChatType { - private Key name; - private int id; - private Map elements; - - enum ElementType { - CHAT, - NARRATION; - - @NotNull - public static ElementType fromString(@NotNull String s) { - return ElementType.valueOf(s.toUpperCase(Locale.ENGLISH)); - } - - @NotNull - public String id() { - return name().toLowerCase(Locale.ENGLISH); - } - } - - @Getter - @Builder - public static class ElementData { - private String translationKey; - private NBTCompound style; - private List parameters; - - @NotNull - public NBTCompound toTag() { - NBTCompound compound = new NBTCompound(); - compound.setTag("translation_key", new NBTString(translationKey)); - if (style != null) { - compound.setTag("style", style); - } - if (parameters != null) { - NBTList parameterList = new NBTList<>(NBTType.STRING); - for (ElementParameter parameter : parameters) { - parameterList.addTag(new NBTString(parameter.id())); - } - compound.setTag("parameters", parameterList); - } - return compound; - } - - enum ElementParameter { - TARGET, - SENDER, - CONTENT; - - @NotNull - public static ElementParameter fromString(@NotNull String s) { - return ElementParameter.valueOf(s.toUpperCase(Locale.ENGLISH)); - } - - @NotNull - public String id() { - return name().toLowerCase(Locale.ENGLISH); - } - - } - } - } - -}