From 19820fcf2a24cc64d4290db5f2b3d0c2a92da240 Mon Sep 17 00:00:00 2001 From: CuongNV <> Date: Tue, 24 Mar 2026 10:58:19 +0700 Subject: [PATCH] Add filter ui chat --- .../Scripts/Chat/UI/ChatPanelUI.cs | 59 +++++++++++++++--- .../Scripts/UI/GamePlay/EC_GameUIMan.cs | 2 +- .../ChatSystem/prefab_ChatSystemUI.prefab | 1 + Assets/Scripts/ChatInputHandler.cs | 34 +++++++++- Assets/Scripts/EC_GameRun.cs | 1 + Assets/Scripts/chat_search.txt | Bin 0 -> 34656 bytes Assets/Scripts/chat_search.txt.meta | 7 +++ 7 files changed, 92 insertions(+), 12 deletions(-) create mode 100644 Assets/Scripts/chat_search.txt create mode 100644 Assets/Scripts/chat_search.txt.meta diff --git a/Assets/PerfectWorld/Scripts/Chat/UI/ChatPanelUI.cs b/Assets/PerfectWorld/Scripts/Chat/UI/ChatPanelUI.cs index 4d85c8bbaf..f3027d924a 100644 --- a/Assets/PerfectWorld/Scripts/Chat/UI/ChatPanelUI.cs +++ b/Assets/PerfectWorld/Scripts/Chat/UI/ChatPanelUI.cs @@ -36,6 +36,8 @@ namespace BrewMonster.Scripts.ChatUI private ObjectPool _pool; private bool _userAtBottom = true; + private ChatChannel _currentFilterChannel = ChatChannel.GP_CHAT_LOCAL; + void Awake() { @@ -84,17 +86,20 @@ namespace BrewMonster.Scripts.ChatUI void OnGetItem(ChatMessageView item) { - item.gameObject.SetActive(true); + if (item != null && item.gameObject != null) + item.gameObject.SetActive(true); } void OnReleaseItem(ChatMessageView item) { - item.gameObject.SetActive(false); + if (item != null && item.gameObject != null) + item.gameObject.SetActive(false); } void OnDestroyItem(ChatMessageView item) { - Destroy(item.gameObject); + if (item != null && item.gameObject != null) + Destroy(item.gameObject); } void OnScrollChanged(Vector2 pos) @@ -123,12 +128,38 @@ namespace BrewMonster.Scripts.ChatUI if (!chatPanelUIGO.activeSelf) return; - AddMessageView(data); + if (ShouldShowMessage(data.channel)) + { + AddMessageView(data); - if (_userAtBottom) - ScrollToBottom(); + if (_userAtBottom) + ScrollToBottom(); + } } + private bool ShouldShowMessage(byte channel) + { + if (_currentFilterChannel == ChatChannel.GP_CHAT_LOCAL) + return true; + if (channel == (byte)ChatChannel.GP_CHAT_MISC) + return true; + return channel == (byte)_currentFilterChannel; + } + + public void SetChannelFilter(ChatChannel filterChannel) + { + if (_currentFilterChannel == filterChannel) + return; + + _currentFilterChannel = filterChannel; + + if (chatPanelUIGO.activeSelf) + { + RefreshVisible(); + } + } + + void AddMessageView(ChatMessageData data) { var view = _pool.Get(); @@ -157,15 +188,25 @@ namespace BrewMonster.Scripts.ChatUI _visibleViews.Clear(); - int start = Mathf.Max(0, _messages.Count - maxVisibleMessages); + // Filter messages based on the current channel selection + var filteredMessages = new List(); + foreach (var msg in _messages) + { + if (ShouldShowMessage(msg.channel)) + { + filteredMessages.Add(msg); + } + } - for (int i = start; i < _messages.Count; i++) + int start = Mathf.Max(0, filteredMessages.Count - maxVisibleMessages); + + for (int i = start; i < filteredMessages.Count; i++) { var view = _pool.Get(); view.transform.SetParent(content, false); view.transform.SetAsLastSibling(); - var data = _messages[i]; + var data = filteredMessages[i]; Sprite icon = _iconCache.ContainsKey(data.channel) ? _iconCache[data.channel] : null; view.Bind(icon, data.message); diff --git a/Assets/PerfectWorld/Scripts/UI/GamePlay/EC_GameUIMan.cs b/Assets/PerfectWorld/Scripts/UI/GamePlay/EC_GameUIMan.cs index 93dcc86fe8..d8615f0de3 100644 --- a/Assets/PerfectWorld/Scripts/UI/GamePlay/EC_GameUIMan.cs +++ b/Assets/PerfectWorld/Scripts/UI/GamePlay/EC_GameUIMan.cs @@ -469,7 +469,7 @@ namespace BrewMonster.UI if (isPlayerChannel && idPlayer > 0) // idPlayer > 0 is equivalent to C++ ISPLAYERID(id) { - // TODO: pszMsg = FilterBadWords(pszMsg); when API is available + CECUIManager.Instance.FilterBadWords(ref pszMsg); } // C++: Booth Message check (cChannel == GP_CHAT_WHISPER && pszMsg ends with "!#") diff --git a/Assets/Prefabs/ChatSystem/prefab_ChatSystemUI.prefab b/Assets/Prefabs/ChatSystem/prefab_ChatSystemUI.prefab index f6db1b6f6a..c7eff41092 100644 --- a/Assets/Prefabs/ChatSystem/prefab_ChatSystemUI.prefab +++ b/Assets/Prefabs/ChatSystem/prefab_ChatSystemUI.prefab @@ -297,6 +297,7 @@ MonoBehaviour: button: {fileID: 1690303811971402318} - channel: 8 button: {fileID: 5620031369785857446} + chatPanelUI: {fileID: 2621697629504226575} --- !u!1 &726262149639511024 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Scripts/ChatInputHandler.cs b/Assets/Scripts/ChatInputHandler.cs index 9c9de1ac44..d5b7b77779 100644 --- a/Assets/Scripts/ChatInputHandler.cs +++ b/Assets/Scripts/ChatInputHandler.cs @@ -21,6 +21,7 @@ namespace BrewMonster.Scripts.ChatUI } public List channelButtons = new(); + public ChatPanelUI chatPanelUI; // Reference to ChatPanelUI to relay channel changes private const int MAX_HISTORY = 10; private ChatChannel m_currentChannel = ChatChannel.GP_CHAT_LOCAL; @@ -88,6 +89,12 @@ namespace BrewMonster.Scripts.ChatUI } m_currentChannel = channel; + + if (chatPanelUI != null) + { + chatPanelUI.SetChannelFilter(channel); + } + var config = chatSystem.channelIcons.Find(c => c.channel == channel); if (config.prefix != null) { @@ -96,8 +103,17 @@ namespace BrewMonster.Scripts.ChatUI inputField.text = config.prefix + currentText; } - inputField.ActivateInputField(); - inputField.MoveTextEnd(false); + if (channel == ChatChannel.GP_CHAT_SYSTEM) + { + inputField.interactable = false; + inputField.text = ""; // Xóa text nếu chuyển sang kênh hệ thống + } + else + { + inputField.interactable = true; + inputField.ActivateInputField(); + inputField.MoveTextEnd(false); + } } private string RemoveKnownPrefix(string text) @@ -306,6 +322,20 @@ namespace BrewMonster.Scripts.ChatUI } // Không gõ prefix thủ công thì sẽ dùng m_currentChannel đã được gán ở đầu hàm + if (channel == ChatChannel.GP_CHAT_SYSTEM) + { + Debug.Log("[Cuong] ParseAndSendMessage Ngăn người chơi chat ở GP_CHAT_SYSTEM"); + return channel; + } + + if (channel == ChatChannel.GP_CHAT_WHISPER) + { + // Nếu người chơi đang ở kênh Whisper nhưng (vô tình) xóa mất dấu '/' + // Ta vẫn giả lập thêm '/' vào để parse theo cú pháp "TênNgườiNhận NộiDung" + HandleWhisper("/" + pszMsg, nPack, nSlot); + return channel; + } + SendChat(channel, pszMsg, nPack, nSlot); return channel; } diff --git a/Assets/Scripts/EC_GameRun.cs b/Assets/Scripts/EC_GameRun.cs index 226ecd3065..6b958ca287 100644 --- a/Assets/Scripts/EC_GameRun.cs +++ b/Assets/Scripts/EC_GameRun.cs @@ -876,6 +876,7 @@ public partial class CECGameRun : ITickable if (string.IsNullOrEmpty(pszMsg)) return; + Debug.Log($"[Cuong] AddChatMessage [{cChannel}] {pszMsgOrigion} {pszMsg}"); CECGameUIMan pGameUI = m_pUIManager?.GetInGameUIMan(); if (pGameUI != null) { diff --git a/Assets/Scripts/chat_search.txt b/Assets/Scripts/chat_search.txt new file mode 100644 index 0000000000000000000000000000000000000000..c9f9dd1faa3093369fe313b18d0c6a26578671c3 GIT binary patch literal 34656 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 Td*G#2?