From ec5e9a6bb9c6fd5d3c5925ff3ceca90194e8ad7f Mon Sep 17 00:00:00 2001 From: CuongNV <> Date: Fri, 10 Apr 2026 14:50:40 +0700 Subject: [PATCH] Add Dropdown --- .../Scripts/Network/CSNetwork/AUICommon.cs | 3 +- .../ChatSystem/prefab_ChatSystemUI.prefab | 8 +- Assets/Scripts/ChatInputHandler.cs | 161 ++++++++++++++++++ 3 files changed, 168 insertions(+), 4 deletions(-) diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/AUICommon.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/AUICommon.cs index ad7cda8294..16b4c07d3a 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/AUICommon.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/AUICommon.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; +using BrewMonster.Scripts.Chat; using CSNetwork; namespace CSNetwork @@ -436,7 +437,7 @@ namespace CSNetwork UnmarshalEmotionInfo(item.GetInfo(), ref nSet, ref nIndex); if (spriteMap.TryGetSprite(nSet, nIndex, out var info)) - sb.Append(BrewMonster.Scripts.Chat.EmotionTMPTagBuilder.BuildSpriteTag(info)); + sb.Append(EmotionTMPTagBuilder.BuildSpriteTag(info)); } else { diff --git a/Assets/Prefabs/ChatSystem/prefab_ChatSystemUI.prefab b/Assets/Prefabs/ChatSystem/prefab_ChatSystemUI.prefab index 811207157d..66e1e24fd8 100644 --- a/Assets/Prefabs/ChatSystem/prefab_ChatSystemUI.prefab +++ b/Assets/Prefabs/ChatSystem/prefab_ChatSystemUI.prefab @@ -248,6 +248,8 @@ MonoBehaviour: button: {fileID: 5620031369785857446} - channel: 1 button: {fileID: 8966563982496817389} + recentWhisperDropdown: {fileID: 747574219879112410} + maxRecentWhisperTargets: 5 --- !u!114 &806784442167936328 MonoBehaviour: m_ObjectHideFlags: 0 @@ -846,9 +848,9 @@ MonoBehaviour: m_fontSize: 20 m_fontSizeBase: 20 m_fontWeight: 400 - m_enableAutoSizing: 0 - m_fontSizeMin: 18 - m_fontSizeMax: 72 + m_enableAutoSizing: 1 + m_fontSizeMin: 15 + m_fontSizeMax: 20 m_fontStyle: 0 m_HorizontalAlignment: 2 m_VerticalAlignment: 4096 diff --git a/Assets/Scripts/ChatInputHandler.cs b/Assets/Scripts/ChatInputHandler.cs index 1c8fff69d2..ada78a2724 100644 --- a/Assets/Scripts/ChatInputHandler.cs +++ b/Assets/Scripts/ChatInputHandler.cs @@ -52,6 +52,31 @@ namespace BrewMonster.Scripts.ChatUI public List channelButtons = new(); + [Header("Channel / whisper dropdown")] + [Tooltip("TMP_Dropdown: 4 kênh (Local/Team/Faction/World) khi không whisper; khi whisper thì hiện MRU tên người. English: TMP_Dropdown — four channels when not whisper; MRU names in whisper.")] + [SerializeField] private TMP_Dropdown recentWhisperDropdown; + + /// Thứ tự kênh trong dropdown (không gồm Whisper). English: Channel order in dropdown (whisper excluded). + private static readonly ChatChannel[] ChatDropdownChannelOrder = + { + ChatChannel.GP_CHAT_LOCAL, + ChatChannel.GP_CHAT_TEAM, + ChatChannel.GP_CHAT_FACTION, + ChatChannel.GP_CHAT_FARCRY, + }; + + [Tooltip("Số người whisper gần nhất tối đa trong dropdown. English: Max recent whisper targets in the dropdown.")] + [SerializeField] private int maxRecentWhisperTargets = 5; + + /// Giới hạn MRU whisper cho UX dropdown (tối thiểu 1). English: MRU whisper cap for dropdown UX (minimum 1). + public int MaxRecentWhisperTargets => Mathf.Max(1, maxRecentWhisperTargets); + + /// Dòng đầu dropdown: không chọn MRU (giữ target đang gõ). English: First row: no MRU pick. + private const string WhisperDropdownPlaceholder = "\u2014"; + + private readonly List m_recentWhispers = new(); + private bool m_whisperDropdownBulkUpdate; + private const int MAX_HISTORY = 10; private ChatChannel m_currentChannel = ChatChannel.GP_CHAT_LOCAL; private string m_whisperTarget = ""; @@ -91,6 +116,9 @@ namespace BrewMonster.Scripts.ChatUI inputField.onSubmit.RemoveListener(OnSubmit); inputField.onValueChanged.RemoveListener(OnInputValueChanged); } + + if (recentWhisperDropdown != null) + recentWhisperDropdown.onValueChanged.RemoveListener(OnChatDropdownValueChanged); } private void OnWhisperPlayerEvent(WhisperPlayerEvent e) @@ -107,6 +135,9 @@ namespace BrewMonster.Scripts.ChatUI if (inputField != null) inputField.onValueChanged.AddListener(OnInputValueChanged); + WireChatDropdown(); + RebuildChatDropdownOptions(); + foreach (var mapping in channelButtons) { if (mapping.button != null) @@ -128,6 +159,8 @@ namespace BrewMonster.Scripts.ChatUI { inputField.shouldHideMobileInput = true; } + + UpdateChatDropdownInteractable(); } // ===================================================== @@ -190,9 +223,122 @@ namespace BrewMonster.Scripts.ChatUI SyncChatWireBodyFromInput(); + RebuildChatDropdownOptions(); + UpdateChatDropdownInteractable(); + EventBus.Publish(new ChatChannelFilterChangedEvent(m_currentChannel)); } + void WireChatDropdown() + { + if (recentWhisperDropdown == null) return; + recentWhisperDropdown.onValueChanged.RemoveListener(OnChatDropdownValueChanged); + recentWhisperDropdown.onValueChanged.AddListener(OnChatDropdownValueChanged); + } + + void UpdateChatDropdownInteractable() + { + if (recentWhisperDropdown == null) return; + recentWhisperDropdown.interactable = m_currentChannel != ChatChannel.GP_CHAT_SYSTEM; + } + + void OnChatDropdownValueChanged(int index) + { + if (m_whisperDropdownBulkUpdate) return; + if (recentWhisperDropdown == null) return; + + if (m_currentChannel == ChatChannel.GP_CHAT_WHISPER) + { + if (index <= 0) return; + int mruIndex = index - 1; + if (mruIndex < 0 || mruIndex >= m_recentWhispers.Count) return; + SetWhisperTarget(m_recentWhispers[mruIndex]); + return; + } + + if (index < 0 || index >= ChatDropdownChannelOrder.Length) return; + ChatChannel ch = ChatDropdownChannelOrder[index]; + if (ch == m_currentChannel) return; + OnCommand_speakmode(ch); + } + + void RebuildChatDropdownOptions() + { + if (recentWhisperDropdown == null) return; + + m_whisperDropdownBulkUpdate = true; + recentWhisperDropdown.ClearOptions(); + + if (m_currentChannel == ChatChannel.GP_CHAT_WHISPER) + { + var whisperOpts = new List + { + new TMP_Dropdown.OptionData(WhisperDropdownPlaceholder) + }; + foreach (var name in m_recentWhispers) + whisperOpts.Add(new TMP_Dropdown.OptionData(name)); + recentWhisperDropdown.AddOptions(whisperOpts); + SyncWhisperMruDropdownSelection(); + } + else + { + var channelOpts = new List(); + foreach (var ch in ChatDropdownChannelOrder) + channelOpts.Add(new TMP_Dropdown.OptionData(GetChannelDropdownLabel(ch))); + recentWhisperDropdown.AddOptions(channelOpts); + SyncPublicChannelDropdownSelection(); + } + + m_whisperDropdownBulkUpdate = false; + } + + void SyncPublicChannelDropdownSelection() + { + if (recentWhisperDropdown == null || recentWhisperDropdown.options.Count == 0) return; + + int idx = 0; + for (int i = 0; i < ChatDropdownChannelOrder.Length; i++) + { + if (ChatDropdownChannelOrder[i] != m_currentChannel) continue; + idx = i; + break; + } + + int max = recentWhisperDropdown.options.Count - 1; + recentWhisperDropdown.SetValueWithoutNotify(Mathf.Clamp(idx, 0, max)); + } + + void SyncWhisperMruDropdownSelection() + { + if (recentWhisperDropdown == null) return; + + int idx = 0; + if (!string.IsNullOrEmpty(m_whisperTarget)) + { + int inMru = m_recentWhispers.IndexOf(m_whisperTarget); + if (inMru >= 0) + idx = inMru + 1; + } + + int max = recentWhisperDropdown.options.Count - 1; + if (max < 0) return; + recentWhisperDropdown.SetValueWithoutNotify(Mathf.Clamp(idx, 0, max)); + } + + void RecordRecentWhisper(string playerName) + { + if (string.IsNullOrEmpty(playerName)) return; + + int cap = MaxRecentWhisperTargets; + m_recentWhispers.Remove(playerName); + m_recentWhispers.Insert(0, playerName); + while (m_recentWhispers.Count > cap) + m_recentWhispers.RemoveAt(m_recentWhispers.Count - 1); + + if (m_currentChannel == ChatChannel.GP_CHAT_WHISPER) + RebuildChatDropdownOptions(); + } + private string RemoveKnownPrefix(string text) { if (string.IsNullOrEmpty(text)) return text; @@ -512,6 +658,8 @@ namespace BrewMonster.Scripts.ChatUI // AddChatMessage sẽ convert &target& thành TMP link tag có dạng idTarget|target pGameUI.AddChatMessage(localMsg, ChatChannel.GP_CHAT_WHISPER, idTarget, null, 0, 0, null, _chatWireBody); } + + RecordRecentWhisper(target); } // [Port] C++: pFriendMan->GetFriendByName(name) → pFriend->id @@ -627,6 +775,19 @@ namespace BrewMonster.Scripts.ChatUI }; } + /// Nhãn hiển thị trên dropdown cho từng kênh công khai. English: Dropdown caption per public channel. + private string GetChannelDropdownLabel(ChatChannel channel) + { + return channel switch + { + ChatChannel.GP_CHAT_LOCAL => "Tự do", + ChatChannel.GP_CHAT_TEAM => "Đội", + ChatChannel.GP_CHAT_FACTION => "Bang", + ChatChannel.GP_CHAT_FARCRY => "Thế giới", + _ => channel.ToString() + }; + } + private bool IsPlayerBlacklisted(int idPlayer) => false; // Placeholder private void ClearTextInInputField()