From d37ba3e804021200c4f0c0b1470114f3251ce9a9 Mon Sep 17 00:00:00 2001 From: Richard Leek Date: Fri, 30 Aug 2024 04:55:14 +0000 Subject: [PATCH] Chat fixes (#358) * Always use other character renderer for public/group chat * Play sound effect when admin chat sent * Make group chat handler use party members instead of map data * Add PM Close clickable areas after tabs and fixed positions * Add SFX for PM target not found * Dispatch right-click handler to chat tab Solution: adjust coordinates (and child control offsets) so chat tabs are *only* the click area (and not the full panel size). Fixes bug where right-clicking would always try to dispatch to the sys tab, which wouldn't have name data for the PM target. * Reset PM targets in login Fixes bug where relogging and attempting to PM a character you'd previously PM'd would not show the chat tab for the PM session. --------- Co-authored-by: Dan Oak Co-authored-by: Ethan Moffat --- EOLib/PacketHandlers/Chat/GroupChatHandler.cs | 40 +++++++------- EndlessClient/Audio/SoundEffectID.cs | 3 +- EndlessClient/Controllers/ChatController.cs | 6 +++ EndlessClient/Controllers/LoginController.cs | 3 ++ .../HUD/Chat/ChatNotificationActions.cs | 2 + EndlessClient/HUD/Chat/ChatPanelTab.cs | 53 +++++++++---------- EndlessClient/HUD/Panels/ChatPanel.cs | 12 +++++ .../OtherCharacterEventSubscriber.cs | 5 +- 8 files changed, 72 insertions(+), 52 deletions(-) diff --git a/EOLib/PacketHandlers/Chat/GroupChatHandler.cs b/EOLib/PacketHandlers/Chat/GroupChatHandler.cs index a7fd534ea..8bb17c8ed 100644 --- a/EOLib/PacketHandlers/Chat/GroupChatHandler.cs +++ b/EOLib/PacketHandlers/Chat/GroupChatHandler.cs @@ -1,55 +1,59 @@ using System.Collections.Generic; using AutomaticTypeMapper; -using EOLib.Domain.Character; using EOLib.Domain.Chat; using EOLib.Domain.Login; -using EOLib.Domain.Map; using EOLib.Domain.Notifiers; +using EOLib.Domain.Party; +using EOLib.Net.Handlers; using Moffat.EndlessOnline.SDK.Protocol.Net; using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using Optional.Collections; namespace EOLib.PacketHandlers.Chat { [AutoMappedType] - public class GroupChatHandler : PlayerChatByIDHandler + public class GroupChatHandler : InGameOnlyPacketHandler { private readonly IChatRepository _chatRepository; + private readonly IPartyDataProvider _partyDataProvider; private readonly IEnumerable _otherCharacterEventNotifiers; private readonly IEnumerable _chatEventNotifiers; + public override PacketFamily Family => PacketFamily.Talk; public override PacketAction Action => PacketAction.Open; public GroupChatHandler(IPlayerInfoProvider playerInfoProvider, - ICurrentMapStateRepository currentMapStateRepository, - ICharacterProvider characterProvider, IChatRepository chatRepository, + IPartyDataProvider partyDataProvider, IEnumerable otherCharacterEventNotifiers, IEnumerable chatEventNotifiers) - : base(playerInfoProvider, currentMapStateRepository, characterProvider) + : base(playerInfoProvider) { _chatRepository = chatRepository; + _partyDataProvider = partyDataProvider; _otherCharacterEventNotifiers = otherCharacterEventNotifiers; _chatEventNotifiers = chatEventNotifiers; } public override bool HandlePacket(TalkOpenServerPacket packet) { - return Handle(packet, packet.PlayerId); - } + _partyDataProvider.Members.SingleOrNone(member => member.CharacterID == packet.PlayerId) + .MatchSome(member => + { + var localChatData = new ChatData(ChatTab.Local, member.Name, packet.Message, ChatIcon.PlayerPartyDark, ChatColor.PM); + _chatRepository.AllChat[ChatTab.Local].Add(localChatData); - protected override void DoTalk(TalkOpenServerPacket packet, Character character) - { - var localChatData = new ChatData(ChatTab.Local, character.Name, packet.Message, ChatIcon.PlayerPartyDark, ChatColor.PM); - _chatRepository.AllChat[ChatTab.Local].Add(localChatData); + var chatData = new ChatData(ChatTab.Group, member.Name, packet.Message, ChatIcon.PlayerPartyDark); + _chatRepository.AllChat[ChatTab.Group].Add(chatData); - var chatData = new ChatData(ChatTab.Group, character.Name, packet.Message, ChatIcon.PlayerPartyDark); - _chatRepository.AllChat[ChatTab.Group].Add(chatData); + foreach (var notifier in _otherCharacterEventNotifiers) + notifier.OtherCharacterSaySomethingToGroup(member.CharacterID, packet.Message); - foreach (var notifier in _otherCharacterEventNotifiers) - notifier.OtherCharacterSaySomethingToGroup(character.ID, packet.Message); + foreach (var notifier in _chatEventNotifiers) + notifier.NotifyChatReceived(ChatEventType.Group); + }); - foreach (var notifier in _chatEventNotifiers) - notifier.NotifyChatReceived(ChatEventType.Group); + return true; } } } diff --git a/EndlessClient/Audio/SoundEffectID.cs b/EndlessClient/Audio/SoundEffectID.cs index e115d387f..21f4863f4 100644 --- a/EndlessClient/Audio/SoundEffectID.cs +++ b/EndlessClient/Audio/SoundEffectID.cs @@ -24,7 +24,7 @@ public enum SoundEffectID PrivateMessageReceived, PunchAttack, UnknownWarpSound, - UnknownPingSound = 12, + PrivateMessageTargetNotFound = 12, HudStatusBarClick, AdminAnnounceReceived, MeleeWeaponAttack, @@ -43,6 +43,7 @@ public enum SoundEffectID Craft, UnknownBuzzSound = 28, AdminChatReceived, + AdminChatSent = AdminChatReceived, AlternateMeleeAttack, PotionOfFlamesEffect, AdminWarp = 32, diff --git a/EndlessClient/Controllers/ChatController.cs b/EndlessClient/Controllers/ChatController.cs index 06984f14d..778bd11c2 100644 --- a/EndlessClient/Controllers/ChatController.cs +++ b/EndlessClient/Controllers/ChatController.cs @@ -60,6 +60,12 @@ public void SendChatAndClearTextBox() } var chatType = _chatTypeCalculator.CalculateChatType(localTypedText); + + if (chatType == ChatType.Admin) + { + _sfxPlayer.PlaySfx(SoundEffectID.AdminChatSent); + } + var (result, updatedChat) = _chatActions.SendChatToServer(localTypedText, targetCharacter, chatType); switch (result) { diff --git a/EndlessClient/Controllers/LoginController.cs b/EndlessClient/Controllers/LoginController.cs index e614866a4..7968a17c1 100644 --- a/EndlessClient/Controllers/LoginController.cs +++ b/EndlessClient/Controllers/LoginController.cs @@ -290,6 +290,9 @@ private void ClearChat() { chat.Clear(); } + + _chatRepository.PMTarget1 = string.Empty; + _chatRepository.PMTarget2 = string.Empty; } private void AddDefaultTextToChat() diff --git a/EndlessClient/HUD/Chat/ChatNotificationActions.cs b/EndlessClient/HUD/Chat/ChatNotificationActions.cs index 9cc3d0283..7a85b5838 100644 --- a/EndlessClient/HUD/Chat/ChatNotificationActions.cs +++ b/EndlessClient/HUD/Chat/ChatNotificationActions.cs @@ -72,6 +72,8 @@ public void NotifyPrivateMessageRecipientNotFound(string recipientName) var chatPanel = _hudControlProvider.GetComponent(HudControlIdentifier.ChatPanel); chatPanel.ClosePMTab(tab); }); + + _sfxPlayer.PlaySfx(SoundEffectID.PrivateMessageTargetNotFound); } public void NotifyPlayerMutedByAdmin(string adminName) diff --git a/EndlessClient/HUD/Chat/ChatPanelTab.cs b/EndlessClient/HUD/Chat/ChatPanelTab.cs index 8b8e530c4..0face3d6e 100644 --- a/EndlessClient/HUD/Chat/ChatPanelTab.cs +++ b/EndlessClient/HUD/Chat/ChatPanelTab.cs @@ -10,7 +10,6 @@ using EOLib; using EOLib.Domain.Chat; using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Input; using MonoGame.Extended.BitmapFonts; using MonoGame.Extended.Input; using MonoGame.Extended.Input.InputListeners; @@ -83,29 +82,29 @@ public ChatPanelTab(IChatProvider chatProvider, _tabSheetUnselected = tabSheetUnselected; _chatFont = chatFont; - DrawArea = new Rectangle(0, 0, _parentPanel.DrawArea.Width, _parentPanel.DrawArea.Height); + DrawArea = GetTabClickableArea(); + + _tab = new ClickableArea(new Rectangle(0, 0, DrawArea.Width, DrawArea.Height)); + _tab.OnClick += (_, _) => SelectThisTab(); + _tab.SetParentControl(this); if (Tab == ChatTab.Private1) { - _closeButton = new ClickableArea(new Rectangle(23, 102, 11, 11)); + _closeButton = new ClickableArea(new Rectangle(3, 3, 11, 11)); _closeButton.OnClick += (_, _) => CloseTab(); _closeButton.SetParentControl(this); } else if (Tab == ChatTab.Private2) { - _closeButton = new ClickableArea(new Rectangle(156, 102, 11, 11)); + _closeButton = new ClickableArea(new Rectangle(3, 3, 11, 11)); _closeButton.OnClick += (_, _) => CloseTab(); _closeButton.SetParentControl(this); } - _tab = new ClickableArea(GetTabClickableArea()); - _tab.OnClick += (_, _) => SelectThisTab(); - _tab.SetParentControl(this); - _label = new XNALabel(Constants.FontSize08) { Text = GetTabTextLabel(), - DrawPosition = GetTabClickableArea().Location.ToVector2() + new Vector2(16, 2) + DrawPosition = new Vector2(16, 2) }; _label.SetParentControl(this); @@ -122,6 +121,21 @@ public override void Initialize() base.Initialize(); } + public void HandleRightClick(MouseEventArgs eventArgs) + { + var clickedYRelativeToTopOfPanel = eventArgs.Position.Y - _parentPanel.DrawAreaWithParentOffset.Y; + var clickedChatRow = (int)Math.Round(clickedYRelativeToTopOfPanel / 13.0) - 1; + + if (clickedChatRow >= 0 && _scrollBar.ScrollOffset + clickedChatRow < _cachedChat.Count) + { + var who = _chatProvider.AllChat[Tab][_scrollBar.ScrollOffset + clickedChatRow].Who; + if (!string.IsNullOrEmpty(who)) + { + _hudControlProvider.GetComponent(HudControlIdentifier.ChatTextBox).Text = $"!{who} "; + } + } + } + public void CloseTab() { if (Tab != ChatTab.Private1 && Tab != ChatTab.Private2) @@ -170,7 +184,7 @@ protected override void OnDrawControl(GameTime gameTime) _spriteBatch.Begin(); var sheet = Active ? _tabSheetSelected : _tabSheetUnselected; - _spriteBatch.Draw(sheet.SheetTexture, _tab.ClickArea.Location.ToVector2() + ImmediateParent.DrawPositionWithParentOffset, sheet.SourceRectangle, Color.White); + _spriteBatch.Draw(sheet.SheetTexture, DrawAreaWithParentOffset, sheet.SourceRectangle, Color.White); if (Active) { @@ -190,25 +204,6 @@ protected override void OnDrawControl(GameTime gameTime) base.OnDrawControl(gameTime); } - protected override bool HandleClick(IXNAControl control, MouseEventArgs eventArgs) - { - if (eventArgs.Button == MouseButton.Right) - { - var clickedYRelativeToTopOfPanel = eventArgs.Position.Y - DrawAreaWithParentOffset.Y; - var clickedChatRow = (int)Math.Round(clickedYRelativeToTopOfPanel / 13.0) - 1; - - if (clickedChatRow >= 0 && _scrollBar.ScrollOffset + clickedChatRow < _cachedChat.Count) - { - var who = _chatProvider.AllChat[Tab][_scrollBar.ScrollOffset + clickedChatRow].Who; - _hudControlProvider.GetComponent(HudControlIdentifier.ChatTextBox).Text = $"!{who} "; - } - - return true; - } - - return false; - } - private void SelectThisTab() { if (!_closeButtonClicked) diff --git a/EndlessClient/HUD/Panels/ChatPanel.cs b/EndlessClient/HUD/Panels/ChatPanel.cs index f8aadde15..0293f6e09 100644 --- a/EndlessClient/HUD/Panels/ChatPanel.cs +++ b/EndlessClient/HUD/Panels/ChatPanel.cs @@ -11,6 +11,8 @@ using EOLib.Graphics; using Microsoft.Xna.Framework; using MonoGame.Extended.BitmapFonts; +using MonoGame.Extended.Input; +using MonoGame.Extended.Input.InputListeners; using XNAControls; namespace EndlessClient.HUD.Panels @@ -132,5 +134,15 @@ public void ClosePMTab(ChatTab whichTab) { _tabs[whichTab].CloseTab(); } + + protected override bool HandleClick(IXNAControl control, MouseEventArgs eventArgs) + { + if (eventArgs.Button == MouseButton.Right) + { + _tabs[CurrentTab].HandleRightClick(eventArgs); + } + + return base.HandleClick(control, eventArgs); + } } } diff --git a/EndlessClient/Subscribers/OtherCharacterEventSubscriber.cs b/EndlessClient/Subscribers/OtherCharacterEventSubscriber.cs index 9924a7d60..f1fe5e07f 100644 --- a/EndlessClient/Subscribers/OtherCharacterEventSubscriber.cs +++ b/EndlessClient/Subscribers/OtherCharacterEventSubscriber.cs @@ -59,11 +59,8 @@ public void AdminAnnounce(string message) private void SaySomethingShared(int characterID, string message, bool isGroupChat) { - if (_characterRendererProvider.CharacterRenderers.TryGetValue(characterID, out var characterRenderer) || - _characterRendererProvider.MainCharacterRenderer.HasValue) + if (_characterRendererProvider.CharacterRenderers.TryGetValue(characterID, out var characterRenderer)) { - _characterRendererProvider.MainCharacterRenderer.MatchSome(x => characterRenderer = x); - var name = characterRenderer.Character.Name; var ignoreList = _friendIgnoreListService.LoadList(Constants.IgnoreListFile);