diff --git a/api/src/main/java/com/velocitypowered/api/event/player/PlayerChatEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/PlayerChatEvent.java new file mode 100644 index 000000000..6df36fb98 --- /dev/null +++ b/api/src/main/java/com/velocitypowered/api/event/player/PlayerChatEvent.java @@ -0,0 +1,97 @@ +package com.velocitypowered.api.event.player; + +import com.google.common.base.Preconditions; +import com.velocitypowered.api.event.ResultedEvent; +import com.velocitypowered.api.proxy.Player; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.Optional; + +/** + * This event is fired once the player has been authenticated but before they connect to a server on the proxy. + */ +public class PlayerChatEvent implements ResultedEvent { + private final Player player; + private final String message; + private ChatResult result; + + public PlayerChatEvent(Player player, String message) { + this.player = Preconditions.checkNotNull(player, "player"); + this.message = Preconditions.checkNotNull(message, "message"); + this.result = ChatResult.allowed(); + } + + public Player getPlayer() { + return player; + } + + public String getMessage() { + return message; + } + + @Override + public ChatResult getResult() { + return result; + } + + @Override + public void setResult(@NonNull ChatResult result) { + this.result = Preconditions.checkNotNull(result, "result"); + } + + @Override + public String toString() { + return "PlayerChatEvent{" + + "player=" + player + + ", message=" + message + + ", result=" + result + + '}'; + } + + /** + * Represents the result of the {@link PlayerChatEvent}. + */ + public static class ChatResult implements ResultedEvent.Result { + private static final ChatResult ALLOWED = new ChatResult(true, null); + private static final ChatResult DENIED = new ChatResult(false, null); + + // The server can not accept formatted text from clients! + private @Nullable String message; + private final boolean allowed; + + protected ChatResult(boolean allowed, @Nullable String message) { + this.allowed = allowed; + this.message = message; + } + + @Override + public boolean isAllowed() { + return allowed; + } + + @Override + public String toString() { + return allowed ? "allowed" : "denied"; + } + + public static ChatResult allowed() { + return ALLOWED; + } + + public static ChatResult denied() { + return DENIED; + } + + public Optional getMessage() { + return Optional.ofNullable(message); + } + + public static ChatResult message(@NonNull String message) { + Preconditions.checkNotNull(message, "message"); + return new ChatResult(true, message); + } + } + + +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index aa27bc1cf..bc0856f8c 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -2,6 +2,7 @@ package com.velocitypowered.proxy.connection.client; import com.velocitypowered.api.event.connection.DisconnectEvent; import com.velocitypowered.api.event.connection.PluginMessageEvent; +import com.velocitypowered.api.event.player.PlayerChatEvent; import com.velocitypowered.api.proxy.messages.ChannelIdentifier; import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.connection.MinecraftSessionHandler; @@ -93,7 +94,15 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { return; } } else { - player.getConnectedServer().getMinecraftConnection().write(chat); + PlayerChatEvent event = new PlayerChatEvent(player, msg); + server.getEventManager().fire(event) + .thenAcceptAsync(pme -> { + if (pme.getResult().equals(PlayerChatEvent.ChatResult.allowed())){ + player.getConnectedServer().getMinecraftConnection().write(chat); + } else if (pme.getResult().isAllowed() && pme.getResult().getMessage().isPresent()){ + player.getConnectedServer().getMinecraftConnection().write(Chat.createServerbound(pme.getResult().getMessage().get())); + } + }, player.getConnectedServer().getMinecraftConnection().getChannel().eventLoop()); } return; }