Files
test/Assets/PerfectWorld/Scripts/UI/UIPlayer.cs
T
2026-03-12 17:26:24 +07:00

195 lines
5.8 KiB
C#

using System;
using System.Threading;
using BrewMonster.Scripts.ChatUI;
using CSNetwork.GPDataType;
using Cysharp.Threading.Tasks;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace BrewMonster.PerfectWorld.Scripts.UI
{
public class UIPlayer : MonoBehaviour
{
[Header("World HUD (optional)")]
public Image healthImage;
[SerializeField] private TextMeshProUGUI nameText;
[SerializeField] private Transform canvasRoot;
[SerializeField] private TextMeshProUGUI chatText;
[Header("References")]
[SerializeField] private CECPlayer hostplayer;
[SerializeField] private float chatDisplayDuration = 5f;
private CancellationTokenSource _chatCts;
private const string DefaultLayerName = "Default";
private bool _isVisible;
private void Awake()
{
CacheRefs();
}
private void Start()
{
CacheRefs();
if (hostplayer == null)
{
Debug.LogError("[UIPlayer] CECPlayer not found in parents.");
return;
}
SetVisible(true);
RefreshName();
EventBus.SubscribeChannel<EventChatMessageOnTopPlayer>(hostplayer.GetCharacterID(), SetChatMessage);
EventBus.SubscribeChannel<cmd_self_info_00>(hostplayer.m_PlayerInfo.cid, UpdateHostPlayerInfoUI);
}
private void OnDestroy()
{
_chatCts?.Cancel();
_chatCts?.Dispose();
if (hostplayer == null)
{
return;
}
EventBus.UnsubscribeChannel<EventChatMessageOnTopPlayer>(hostplayer.GetCharacterID(), SetChatMessage);
EventBus.UnsubscribeChannel<cmd_self_info_00>(hostplayer.m_PlayerInfo.cid, UpdateHostPlayerInfoUI);
}
private void UpdateHostPlayerInfoUI(cmd_self_info_00 obj)
{
//healthText.text = $"{obj.iHP}/{obj.iMaxHP}";
if (healthImage != null && obj.iMaxHP > 0)
healthImage.fillAmount = (float)obj.iHP / obj.iMaxHP;
}
public void SetVisible(bool visible)
{
_isVisible = visible;
if (canvasRoot == null)
return;
if (visible)
{
int defaultLayer = LayerMask.NameToLayer(DefaultLayerName);
if (defaultLayer < 0) defaultLayer = 0;
SetLayerRecursively(canvasRoot.gameObject, defaultLayer);
RefreshName();
}
canvasRoot.gameObject.SetActive(visible);
}
public bool IsVisible() => _isVisible;
public void RefreshName()
{
if (nameText == null || hostplayer == null)
return;
var n = hostplayer.GetName();
if (string.IsNullOrWhiteSpace(n))
n = hostplayer.gameObject != null ? hostplayer.gameObject.name : "";
if (!string.IsNullOrWhiteSpace(n))
nameText.text = n;
}
private void CacheRefs()
{
if (hostplayer == null)
hostplayer = GetComponentInParent<CECPlayer>();
if (canvasRoot == null)
{
var t = transform.Find("Canvas");
if (t != null) canvasRoot = t;
}
if (nameText == null)
{
var named = transform.GetComponentsInChildren<TextMeshProUGUI>(true);
foreach (var tmp in named)
{
if (tmp != null && tmp.gameObject.name.Contains("Name", StringComparison.OrdinalIgnoreCase))
{
nameText = tmp;
break;
}
}
}
}
private static void SetLayerRecursively(GameObject obj, int layer)
{
if (obj == null) return;
obj.layer = layer;
var t = obj.transform;
for (int i = 0; i < t.childCount; i++)
SetLayerRecursively(t.GetChild(i).gameObject, layer);
}
private void SetChatMessage(EventChatMessageOnTopPlayer cxt)
{
if (chatText == null)
{
BMLogger.LogError("Don't have chatText TMProUI");
return;
}
ChatThreadDispatcher.Instance.Post(() =>{
SetLastSaidWords(cxt.context);
});
}
public void SetLastSaidWords(string message, float duration = -1f)
{
if (chatText == null || string.IsNullOrEmpty(message))
return;
chatText.text = message;
chatText.gameObject.SetActive(true);
// cancel timer cũ
_chatCts?.Cancel();
_chatCts = new CancellationTokenSource();
float time = duration > 0 ? duration : chatDisplayDuration;
HideChatAsync(time, _chatCts.Token).Forget();
}
private async UniTaskVoid HideChatAsync(float time, CancellationToken token)
{
try
{
await UniTask.Delay(
TimeSpan.FromSeconds(time),
cancellationToken: token
);
if (chatText != null)
chatText.gameObject.SetActive(false);
}
catch (OperationCanceledException)
{
// chat mới đến → timer cũ bị cancel
}
}
}
public struct EventChatMessageOnTopPlayer
{
public int roleId;
public string context;
public EventChatMessageOnTopPlayer(int roleId, string context)
{
this.roleId = roleId;
this.context = context;
}
}
}