diff --git a/src/main/java/emu/grasscutter/game/chat/ChatSystem.java b/src/main/java/emu/grasscutter/game/chat/ChatSystem.java index 6a5c89840..d95138acb 100644 --- a/src/main/java/emu/grasscutter/game/chat/ChatSystem.java +++ b/src/main/java/emu/grasscutter/game/chat/ChatSystem.java @@ -1,23 +1,25 @@ package emu.grasscutter.game.chat; -import static emu.grasscutter.config.Configuration.GAME_INFO; - import emu.grasscutter.GameConstants; import emu.grasscutter.command.CommandMap; import emu.grasscutter.game.player.Player; import emu.grasscutter.net.proto.ChatInfoOuterClass.ChatInfo; +import emu.grasscutter.server.event.player.PlayerChatEvent; import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.packet.send.PacketPlayerChatNotify; import emu.grasscutter.server.packet.send.PacketPrivateChatNotify; import emu.grasscutter.server.packet.send.PacketPullPrivateChatRsp; import emu.grasscutter.server.packet.send.PacketPullRecentChatRsp; import emu.grasscutter.utils.Utils; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; +import static emu.grasscutter.config.Configuration.GAME_INFO; + public class ChatSystem implements ChatSystemHandler { static final String PREFIXES = "[/!]"; static final Pattern RE_PREFIXES = Pattern.compile(PREFIXES); @@ -133,12 +135,22 @@ public class ChatSystem implements ChatSystemHandler { } // Get target. - Player target = getServer().getPlayerByUid(targetUid); - + var target = getServer().getPlayerByUid(targetUid); if (target == null && targetUid != GameConstants.SERVER_CONSOLE_UID) { return; } + // Invoke the chat event. + var event = new PlayerChatEvent(player, message, target); + event.call(); if (event.isCanceled()) return; + + // Fetch the new target. + targetUid = event.getTargetUid(); + if (targetUid == -1) return; + // Fetch the new message. + message = event.getMessage(); + if (message == null || message.length() == 0) return; + // Create chat packet. var packet = new PacketPrivateChatNotify(player.getUid(), targetUid, message); @@ -147,32 +159,42 @@ public class ChatSystem implements ChatSystemHandler { putInHistory(player.getUid(), targetUid, packet.getChatInfo()); // Check if command - boolean isCommand = tryInvokeCommand(player, target, message); + var isCommand = tryInvokeCommand(player, target, message); - if ((target != null) && (!isCommand)) { + if (target != null && !isCommand) { target.sendPacket(packet); - putInHistory(targetUid, player.getUid(), packet.getChatInfo()); + this.putInHistory(targetUid, player.getUid(), packet.getChatInfo()); } } public void sendPrivateMessage(Player player, int targetUid, int emote) { // Get target. - Player target = getServer().getPlayerByUid(targetUid); - + var target = getServer().getPlayerByUid(targetUid); if (target == null && targetUid != GameConstants.SERVER_CONSOLE_UID) { return; } + // Invoke the chat event. + var event = new PlayerChatEvent(player, emote, target); + event.call(); if (event.isCanceled()) return; + + // Fetch the new target. + targetUid = event.getTargetUid(); + if (targetUid == -1) return; + // Fetch the new emote. + emote = event.getMessageAsInt(); + if (emote == -1) return; + // Create chat packet. - var packet = new PacketPrivateChatNotify(player.getUid(), target.getUid(), emote); + var packet = new PacketPrivateChatNotify(player.getUid(), targetUid, emote); // Send and put is history. player.sendPacket(packet); - putInHistory(player.getUid(), targetUid, packet.getChatInfo()); + this.putInHistory(player.getUid(), targetUid, packet.getChatInfo()); if (target != null) { target.sendPacket(packet); - putInHistory(targetUid, player.getUid(), packet.getChatInfo()); + this.putInHistory(targetUid, player.getUid(), packet.getChatInfo()); } } @@ -183,15 +205,37 @@ public class ChatSystem implements ChatSystemHandler { } // Check if command - if (tryInvokeCommand(player, null, message)) { + if (this.tryInvokeCommand(player, null, message)) { return; } + // Invoke the chat event. + var event = new PlayerChatEvent(player, message, channel); + event.call(); if (event.isCanceled()) return; + + // Fetch the new message. + message = event.getMessage(); + if (message == null || message.length() == 0) return; + // Fetch the new channel. + channel = event.getChannel(); + if (channel == -1) return; + // Create and send chat packet player.getWorld().broadcastPacket(new PacketPlayerChatNotify(player, channel, message)); } public void sendTeamMessage(Player player, int channel, int icon) { + // Invoke the chat event. + var event = new PlayerChatEvent(player, icon, channel); + event.call(); if (event.isCanceled()) return; + + // Fetch the new icon. + icon = event.getMessageAsInt(); + if (icon == -1) return; + // Fetch the new channel. + channel = event.getChannel(); + if (channel == -1) return; + // Create and send chat packet player.getWorld().broadcastPacket(new PacketPlayerChatNotify(player, channel, icon)); } diff --git a/src/main/java/emu/grasscutter/server/event/player/PlayerChatEvent.java b/src/main/java/emu/grasscutter/server/event/player/PlayerChatEvent.java new file mode 100644 index 000000000..ccf79ef4e --- /dev/null +++ b/src/main/java/emu/grasscutter/server/event/player/PlayerChatEvent.java @@ -0,0 +1,79 @@ +package emu.grasscutter.server.event.player; + +import emu.grasscutter.game.player.Player; +import emu.grasscutter.server.event.Cancellable; +import emu.grasscutter.server.event.types.PlayerEvent; +import lombok.Getter; +import lombok.Setter; + +import javax.annotation.Nullable; + +@Getter @Setter +public final class PlayerChatEvent extends PlayerEvent implements Cancellable { + private String message; + + /** + * This field being null signifies a message is being sent to a public chat. + * This can include either a global chat or a team chat. + */ + @Nullable private Player to; + + /** + * This field is not null when the message is being sent to a public chat. + * Refer to {@link #to} for more information. + */ + @Nullable private Integer channelId; + + public PlayerChatEvent(Player player, String message, @Nullable Player to) { + super(player); + + this.message = message; + this.to = to; + } + + public PlayerChatEvent(Player player, int emoteId, @Nullable Player to) { + super(player); + + this.message = String.valueOf(emoteId); + this.to = to; + } + + public PlayerChatEvent(Player player, String message, int channelId) { + super(player); + + this.message = message; + this.channelId = channelId; + } + + public PlayerChatEvent(Player player, int emoteId, int channelId) { + super(player); + + this.message = String.valueOf(emoteId); + this.channelId = channelId; + } + + /** + * @return The target player's UID. + */ + public int getTargetUid() { + return this.to == null ? -1 : this.to.getUid(); + } + + /** + * @return The message as an integer, or -1 if it's not an integer. + */ + public int getMessageAsInt() { + try { + return Integer.parseInt(this.message); + } catch (NumberFormatException e) { + return -1; + } + } + + /** + * @return The channel ID, or -1 if it's not a channel message. + */ + public int getChannel() { + return this.channelId == null ? -1 : this.channelId; + } +}