// // Licensed under the MIT License. See LICENSE file in the project root for full license information. // namespace MUnique.OpenMU.GameLogic.PlayerActions.Chat; using MUnique.OpenMU.GameLogic.Views; /// /// Action to send chat messages. /// public class ChatMessageAction { private readonly IDictionary _messagePrefixes; private readonly IDictionary _chatProcessMessages; /// /// Initializes a new instance of the class. /// public ChatMessageAction() { this._messagePrefixes = new SortedDictionary(new ReverseComparer()) { { "~", ChatMessageType.Party }, { "@", ChatMessageType.Guild }, { "@@", ChatMessageType.Alliance }, { "$", ChatMessageType.Gens }, { "!", ChatMessageType.GlobalNotification }, { "/", ChatMessageType.Command }, }; this._chatProcessMessages = new Dictionary { { ChatMessageType.Command, new ChatMessageCommandProcessor() }, { ChatMessageType.Whisper, new ChatMessageWhisperProcessor() }, { ChatMessageType.Party, new ChatMessagePartyProcessor() }, { ChatMessageType.Alliance, new ChatMessageAllianceProcessor() }, { ChatMessageType.Guild, new ChatMessageGuildProcessor() }, { ChatMessageType.GlobalNotification, new ChatMessageGlobalNotificationProcessor() }, { ChatMessageType.Normal, new ChatMessageNormalProcessor() }, }; } /// /// Sends a chat message from the player to other players. /// /// The sender. /// Name of the , except for , then its the receiver name. /// The message which should be sent. /// If set to true the message is whispered to the player with the ; Otherwise, it's not a whisper. public async ValueTask ChatMessageAsync(Player sender, string playerName, string message, bool whisper) { using var loggerScope = sender.Logger.BeginScope(this.GetType()); ChatMessageType messageType = this.GetMessageType(message, whisper); if (sender.SelectedCharacter is null) { // Is possible to receive null? return; } if (messageType != ChatMessageType.Whisper && playerName != sender.SelectedCharacter?.Name) { sender.Logger.LogWarning("Maybe Hacker, Charname in chat packet != charname\t [{0}] <> [{1}]", sender.SelectedCharacter?.Name, playerName); } if (!this._chatProcessMessages.ContainsKey(messageType)) { sender.Logger.LogDebug("Not implemented chat message type: {0}", messageType); return; } await this._chatProcessMessages[messageType].ProcessMessageAsync(sender, (message, playerName)).ConfigureAwait(true); } private ChatMessageType GetMessageType(string message, bool whisper) { if (whisper) { return ChatMessageType.Whisper; } // byte 13: begin message foreach (var keyValuePair in this._messagePrefixes) { if (message.StartsWith(keyValuePair.Key, StringComparison.InvariantCulture)) { return keyValuePair.Value; } } return ChatMessageType.Normal; } /// /// We have to implement a reverse comparer, so that the strings which are longer, come first. /// private class ReverseComparer : IComparer { public int Compare(string? x, string? y) { return string.Compare(y, x, StringComparison.InvariantCultureIgnoreCase); } } }