using UnityEngine; using TMPro; using UnityEngine.EventSystems; using BrewMonster.Scripts.Task.UI; using System.Collections.Generic; using BrewMonster.UI; using System.Text; using System.Text.RegularExpressions; namespace BrewMonster { public class StyledTaskTraceText : MonoBehaviour, IPointerClickHandler { public TMP_Text tmp; private List linkCommands =new List(); private void Start() { tmp.raycastTarget = true; tmp.ForceMeshUpdate(); } // Helper method to find intersecting link with proper camera handling // 辅助方法,用于查找相交的链接并正确处理相机 private int FindIntersectingLink(PointerEventData eventData) { if (tmp == null) return -1; tmp.ForceMeshUpdate(); // Get camera for link detection // 获取用于链接检测的相机 Camera camera = null; Canvas canvas = tmp.GetComponentInParent(); if (canvas != null) { // IMPORTANT: TMP_TextUtilities.FindIntersectingLink expects camera=null for ScreenSpaceOverlay. // 重要:ScreenSpaceOverlay 必须传 camera=null,否则会算错导致 linkIndex = -1。 if (canvas.renderMode == RenderMode.ScreenSpaceOverlay) { camera = null; } else { // ScreenSpaceCamera / WorldSpace camera = eventData.pressEventCamera != null ? eventData.pressEventCamera : canvas.worldCamera; } } else { // No canvas found; fall back to pressEventCamera (may be null) then main camera = eventData.pressEventCamera != null ? eventData.pressEventCamera : Camera.main; } // Try with camera first, then fallback to null // 先尝试使用相机,然后回退到null int linkIndexCam = TMP_TextUtilities.FindIntersectingLink(tmp, eventData.position, camera); int linkIndexNull = TMP_TextUtilities.FindIntersectingLink(tmp, eventData.position, null); return linkIndexCam != -1 ? linkIndexCam : linkIndexNull; } public void Set(string text) { tmp.text = FormatForTextMeshPro(text); } public static string FormatForTextMeshPro(string text) { if (string.IsNullOrEmpty(text)) return string.Empty; StringBuilder result = new StringBuilder(text); result.Replace("\\r", "\n"); return ProcessColorCodes(result); } public static string ProcessColorCodes(StringBuilder text) { string pattern = @"\^([0-9A-Fa-f]{6})"; return Regex.Replace(text.ToString(), pattern, match => { string hexColor = match.Groups[1].Value; return $""; }, RegexOptions.None); } public void AddToFirstPosition(LinkCommand linkCommand) { linkCommands.Insert(0, linkCommand); } public void AddToLastPosition(LinkCommand linkCommand) { linkCommands.Add(linkCommand); } public void AddLinkCommand(LinkCommand linkCommand) { linkCommands.Add(linkCommand); } public void RemoveLinkCommand(int linkIndex) { linkCommands.RemoveAt(linkIndex); } public void RefreshLinkCommands() { tmp.text = ""; linkCommands.Clear(); } public void OnPointerClick(PointerEventData eventData) { if (tmp == null) return; // Detect link directly in click handler // 在点击处理程序中直接检测链接 int linkIndex = FindIntersectingLink(eventData); // Validate link index // 验证链接索引 if (linkIndex == -1 || linkIndex >= tmp.textInfo.linkCount || linkIndex >= linkCommands.Count) { return; } tmp.ForceMeshUpdate(); TMP_LinkInfo linkInfo = tmp.textInfo.linkInfo[linkIndex]; string linkText = linkInfo.GetLinkText(); string entityID = linkInfo.GetLinkID(); switch (entityID) { case "coord": if (linkIndex < linkCommands.Count && linkCommands[linkIndex] != null) { linkCommands[linkIndex].Execute(tmp); } //Debug.Log($"[StyledTaskTraceText] OnPointerClick: linkCommands[{linkIndex}].Execute(tmp) => {linkCommands[linkIndex].Execute(tmp)}"); break; case "npc": if (linkIndex < linkCommands.Count && linkCommands[linkIndex] != null) { linkCommands[linkIndex].Execute(tmp); } break; case "monster": break; default: Debug.Log($"Clicked unknown link: ID={entityID} Text={linkText}"); break; } } } }