using System; using System.Collections; using System.Collections.Generic; using TMPro; using UnityEngine; using UnityEngine.UI; using XWorld.Framework.Protocol; using UObject = UnityEngine.Object; namespace XGame { public sealed class WorldChatModule : MonoBehaviour { private const string ChatPrefabPath = "Assets/Game/Art/UI/Prefab/UI_CommonChat.prefab"; private const int MaxMessages = 80; private const int MaxInputLength = 200; private GameObject view; private GameObject panelCollapsed; private GameObject panelChat; private Transform contentMessages; private GameObject otherTemplate; private GameObject selfTemplate; private TMP_InputField inputField; private TMP_Text inputPlaceholder; private TMP_Text inputValue; private ScrollRect scrollMessages; private bool opening; private int openVersion; private int localPlayerId; private readonly Queue messageRows = new Queue(); public Action OnSendWorldChat; public bool IsOpen => view != null; public void Initialize(int playerId, Action sendWorldChat) { localPlayerId = playerId; OnSendWorldChat = sendWorldChat; } public IEnumerator OpenAsync() { if (view != null || opening) { yield break; } opening = true; int version = ++openVersion; UObject loaded = null; yield return XResLoader.coLoadRes(ChatPrefabPath, typeof(GameObject), obj => loaded = obj); opening = false; if (version != openVersion) { yield break; } GameObject prefab = loaded as GameObject; if (prefab == null) { Debug.LogError("[WorldChatModule] load chat prefab failed: " + ChatPrefabPath); yield break; } view = Instantiate(prefab); UIManager.AttachTo(UILayer.Normal, view); CacheControls(); BindEvents(); Collapse(); } public void Close() { openVersion++; if (view != null) { Destroy(view); view = null; } messageRows.Clear(); panelCollapsed = null; panelChat = null; contentMessages = null; otherTemplate = null; selfTemplate = null; inputField = null; inputPlaceholder = null; inputValue = null; scrollMessages = null; opening = false; } public void HandleWorldChatMessage(WorldChatMessageMsg message) { if (message == null) { return; } if (view == null) { XWCoroutine.StartCo(OpenThenAppend(message)); return; } AppendMessage(message); } private IEnumerator OpenThenAppend(WorldChatMessageMsg message) { yield return OpenAsync(); AppendMessage(message); } private void CacheControls() { if (view == null) { return; } panelCollapsed = FindGameObject("Panel_Collapsed"); panelChat = FindGameObject("Panel_Chat"); contentMessages = FindTransform("Content_Messages"); otherTemplate = FindGameObject("Item_MessageOther_Template"); selfTemplate = FindGameObject("Item_MessageSelf_Template"); scrollMessages = FindComponent("Scroll_Messages"); inputPlaceholder = FindComponent("Txt_InputPlaceholder"); inputValue = FindComponent("Txt_InputValue"); EnsureInputField(); } private void BindEvents() { BindButton("Btn_CollapsedInput", Expand); BindButton("Btn_Close", Collapse); BindButton("Btn_Send", SendCurrentInput); BindButton("Btn_ClearInput", ClearInput); BindButton("InputHitArea", FocusInput); if (inputField != null) { inputField.onSubmit.RemoveListener(OnInputSubmitted); inputField.onSubmit.AddListener(OnInputSubmitted); } } private void EnsureInputField() { Transform hitArea = FindTransform("InputHitArea"); if (hitArea == null) { return; } inputField = hitArea.GetComponent(); if (inputField == null) { inputField = hitArea.gameObject.AddComponent(); } Button button = hitArea.GetComponent