235 lines
7.9 KiB
C#
235 lines
7.9 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using asap.core;
|
||
using cfg;
|
||
using TimeManager;
|
||
using TMPro;
|
||
using UniRx;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
namespace Activity.HomeEntranceBtn
|
||
{
|
||
public abstract class AbstractHomeEntranceBtn<TData> : EventButtonResource,IHomeEntranceBtn where TData : IEventData,new ()
|
||
{
|
||
#region abstract
|
||
/// <summary>
|
||
/// 关联的 Sentry 类型,子类必须实现
|
||
/// </summary>
|
||
protected abstract Type AssociatedSentryType { get; }
|
||
protected abstract void OnClickBtn();
|
||
protected abstract string GetIconName();
|
||
/// <summary>
|
||
/// 检查并预加载活动资源(子类实现)
|
||
/// </summary>
|
||
protected abstract List<string> GetResourceNames();
|
||
|
||
#endregion
|
||
|
||
#region Data
|
||
|
||
protected AEventDataManager _manager;
|
||
private TData _data;
|
||
/// <summary>
|
||
/// 数据属性,子类无需重写,基类自动处理新账号无数据的情况
|
||
/// </summary>
|
||
protected virtual TData Data
|
||
{
|
||
get
|
||
{
|
||
if(_manager!=null)
|
||
_data = _manager.LoadData<TData>();
|
||
return _data;
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region UIElement
|
||
|
||
[SerializeField] protected TMP_Text textTimer;
|
||
[SerializeField] protected Button btn;
|
||
[SerializeField] protected Image icon;
|
||
|
||
#endregion
|
||
|
||
protected CompositeDisposable _disposable;
|
||
// 缓存数据对象,避免每秒创建新对象
|
||
protected TData _cachedData;
|
||
|
||
protected virtual void Awake()
|
||
{
|
||
if (!textTimer)
|
||
textTimer = gameObject.FindChildGameObject("text_time").GetComponent<TMP_Text>();
|
||
if (!btn)
|
||
btn = gameObject.GetComponent<Button>();
|
||
if (!icon)
|
||
icon = gameObject.FindChildGameObject("icon_task").GetComponent<Image>();
|
||
gameObject.SetActive(false);
|
||
btn.onClick.AddListener(OnClickBtn);
|
||
RegisterBtnInSentry();
|
||
}
|
||
|
||
protected override void OnDestroy()
|
||
{
|
||
_data = default;
|
||
_disposable?.Dispose();
|
||
UnRegisterBtnInSentry();
|
||
base.OnDestroy();
|
||
}
|
||
|
||
protected virtual void UpdateTimer(long _ = 0L)
|
||
{
|
||
gameObject.SetActive(IsActivityActive());
|
||
textTimer.text = ConvertTools.ConvertTime2(_cachedData?.RemainingTime ?? TimeSpan.Zero);
|
||
}
|
||
|
||
protected virtual bool IsActivityActive()
|
||
{
|
||
if (_cachedData == null)
|
||
return Data?.IsActive ?? false;
|
||
return _cachedData?.IsActive ?? false;
|
||
}
|
||
protected bool IsCompletedLoadResource = false;
|
||
protected override async void OnLoadEventResource()
|
||
{
|
||
try
|
||
{
|
||
// 如果已经订阅过,不再重复订阅
|
||
if (_disposable == null)
|
||
{
|
||
_disposable = new CompositeDisposable();
|
||
GContext.OnEvent<TData>().Subscribe(UpdateData).AddTo(_disposable);
|
||
GContext.container.Resolve<ITimeTickService>()?.SecondTick?.Subscribe(UpdateTimer).AddTo(_disposable);
|
||
}
|
||
|
||
_cachedData = Data;
|
||
if (_cachedData != null && IsActivityActive())
|
||
{
|
||
if(IsCompletedLoadResource)
|
||
return;
|
||
IsCompletedLoadResource = true;
|
||
}
|
||
|
||
UpdateTimer();
|
||
await GContext.container.Resolve<IUIService>().SetImageSprite(icon, GetIconName());
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Debug.LogError(e);
|
||
}
|
||
}
|
||
|
||
private void UpdateData(TData data)
|
||
{
|
||
if (data == null || data.EventID != _cachedData.EventID) return;
|
||
_cachedData = Data;
|
||
UpdateTimer();
|
||
}
|
||
/// <summary>
|
||
/// 活动激活时调用,预加载活动资源
|
||
/// </summary>
|
||
public virtual void OnOpen(FishingEvent @event,AEventDataManager manager)
|
||
{
|
||
_manager = manager;
|
||
// 具体资源检查由子类实现
|
||
var resources = GetResourceNames();
|
||
if(resources is { Count: > 0 })
|
||
CheckResource(resources, ReChecking: true);
|
||
else
|
||
OnLoadEventResource();
|
||
}
|
||
/// <summary>
|
||
/// 活动关闭时调用
|
||
/// </summary>
|
||
public virtual void OnClose(FishingEvent fishingEvent)
|
||
{
|
||
gameObject.SetActive(false);
|
||
_disposable?.Dispose();
|
||
_disposable = null;
|
||
|
||
_manager = null;
|
||
_data = default;
|
||
_cachedData = default;
|
||
IsCompletedLoadResource = false;
|
||
}
|
||
/// <summary>
|
||
/// 从关联的 Sentry 类型中获取类型键(使用缓存,零反射开销)
|
||
/// </summary>
|
||
private (int EventType, int EventSubType) GetTypeKeyFromSentry()
|
||
{
|
||
var typeKey = Activity.ActivitySentryManager.GetTypeKey(AssociatedSentryType);
|
||
|
||
if (typeKey == null)
|
||
{
|
||
Debug.LogError(
|
||
$"[{GetType().Name}] Sentry type {AssociatedSentryType.Name} is not registered in ActivitySentryManager. " +
|
||
"Please ensure the Sentry class is decorated with [ActivitySentry(eventType, eventSubType)] " +
|
||
"and is being discovered during initialization.");
|
||
return default;
|
||
}
|
||
|
||
return typeKey.Value;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 注册按钮到 Sentry(虚方法,子类可重写)
|
||
/// </summary>
|
||
public virtual void RegisterBtnInSentry()
|
||
{
|
||
try
|
||
{
|
||
var typeKey = GetTypeKeyFromSentry();
|
||
var sentry = GContext.container.Resolve<ActivityManager>().GetSentry(typeKey);
|
||
|
||
if (sentry == null)
|
||
{
|
||
Debug.LogWarning($"[{GetType().Name}] No sentry found for event type ({typeKey.EventType}, {typeKey.EventSubType})");
|
||
return;
|
||
}
|
||
if (sentry.HomeEntranceBtn != null && (AbstractHomeEntranceBtn<TData>)sentry.HomeEntranceBtn == this)
|
||
{
|
||
Debug.LogWarning($"[{GetType().Name}] Sentry already has button registered: {sentry.HomeEntranceBtn.GetType().Name} sentry.HomeEntranceBtn {sentry.HomeEntranceBtn.GetHashCode()} this {GetHashCode()}");
|
||
return;
|
||
}
|
||
|
||
sentry.RegisterHomeEntranceBtn(this);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Debug.LogError($"[{GetType().Name}] Failed to register in Sentry: {ex.Message}");
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 注册按钮到 Sentry(虚方法,子类可重写)
|
||
/// </summary>
|
||
public virtual void UnRegisterBtnInSentry()
|
||
{
|
||
try
|
||
{
|
||
// 检查容器是否已被销毁
|
||
if (GContext.container == null)
|
||
return;
|
||
|
||
var activityManager = GContext.container.Resolve<ActivityManager>();
|
||
if (activityManager == null)
|
||
return;
|
||
|
||
var typeKey = GetTypeKeyFromSentry();
|
||
var sentry = activityManager.GetSentry(typeKey);
|
||
|
||
if (sentry == null)
|
||
{
|
||
Debug.LogWarning($"[{GetType().Name}] No sentry found for event type ({typeKey.EventType}, {typeKey.EventSubType})");
|
||
return;
|
||
}
|
||
|
||
sentry.UnregisterHomeEntranceBtn();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Debug.LogError($"[{GetType().Name}] Failed to unregister in Sentry: {ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
}
|