yyl
8 天以前 b0ce53afc8346e1391807618e64bdb225e83fd64
Merge branch 'master' of http://192.168.1.20:10010/r/Project_SG_scripts
8个文件已添加
10个文件已修改
1410 ■■■■ 已修改文件
Main/Core/ResModule/GameObjectPoolManager.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/ArenaBattleWin.cs 163 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BaseBattleWin.cs 279 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BaseBattleWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleDebug.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/StoryBattleField.cs 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BoneFieldBattleWin.cs 184 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/StoryBossBattleWin.cs 229 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/BillboardRank/RankModel.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/ChallengeTab/ArenaTabHandler.cs 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/ChallengeTab/ArenaTabHandler.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/ChallengeTab/BaseChallengeTabHandler.cs 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/ChallengeTab/BaseChallengeTabHandler.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/ChallengeTab/BoneFieldTabHandler.cs 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/ChallengeTab/BoneFieldTabHandler.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/ChallengeTab/ChallengeTabButton.cs 88 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/ChallengeTab/ChallengeTabWin.cs 140 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/NewBieGuidance/NewBieWin.cs 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/ResModule/GameObjectPoolManager.cs
@@ -346,7 +346,7 @@
        public HashSet<GameObject> m_ActiveHashSet = new HashSet<GameObject>();
        public Queue<GameObject> m_FreeQueue = null;
        private int Pool_FreeList_Warning_Threshold = 10;    //当空闲对象高于此值时,会进行日志输出提醒
        private int Pool_FreeList_Warning_Threshold = 50;    //当空闲对象高于此值时,会进行日志输出提醒
        Action<GameObject> releaseCallBack;
Main/System/Battle/ArenaBattleWin.cs
@@ -1,20 +1,10 @@
using System.Collections.Generic;
using LitJson;
using UnityEngine;
using UnityEngine.UI;
public class ArenaBattleWin : UIBase
public class ArenaBattleWin : BaseBattleWin
{
    // 组件引用
    [SerializeField] Transform mountPoint;
    [SerializeField] Transform transButtons;
    [SerializeField] Button btnSpeed;
    [SerializeField] Text textSpeed;
    [SerializeField] Button btnPass;
    [SerializeField] Button btnPause;
    private BattleRootNode battleRootNode = null;
    private BattleField battleField;
    [SerializeField] HeroCountryComponent myCountry;
    [SerializeField] TextEx txtMyLV;
    [SerializeField] TextEx txtMyName;
@@ -33,55 +23,30 @@
    [SerializeField] AvatarCell enemyAvatarCell;
    [SerializeField] List<ArenaHeroHead> enemyHeroHeads;
    [SerializeField] TextEx txtWaveInfo;
    public TotalDamageDisplayer totalDamageDisplayer;
    public SkillTips skillTipsRed;
    public SkillTips skillTipsBlue;
    // 生命周期
    protected override void InitComponent()
    protected override void RegisterBattleEvents()
    {
        base.InitComponent();
        // 初始化组件引用 绑定按钮等UI组件事件
        btnSpeed.AddListener(ChangeSpeed);
        btnPass.AddListener(OnClickPass);
        btnPause.AddListener(OnClickPause);
        base.RegisterBattleEvents();
        EventBroadcast.Instance.AddListener<string, JsonData>(EventName.BATTLE_END, OnBattleEnd);
    }
    private void OnClickPause()
    protected override void UnregisterBattleEvents()
    {
        if (null == battleField)
            return;
        battleField.IsPause = !battleField.IsPause;
        base.UnregisterBattleEvents();
        EventBroadcast.Instance.RemoveListener<string, JsonData>(EventName.BATTLE_END, OnBattleEnd);
    }
    private void OnClickPass()
    protected virtual void OnBattleEnd(string guid, JsonData endData)
    {
        if (null == battleField)
            return;
        battleField.ForceFinish();
    }
    private void ChangeSpeed()
    {
        if (null == battleField)
            return;
        BattleManager.Instance.speedIndex = (BattleManager.Instance.speedIndex + 1) % BattleManager.Instance.speedGear.Length;
        battleField.SetSpeedRatio(BattleManager.Instance.speedGear[BattleManager.Instance.speedIndex]);
        textSpeed.text = (BattleManager.Instance.speedIndex + 1).ToString();
        if (battleField != null && guid == battleField.guid)
        {
            DisplayHpInfo();
        }
    }
    protected override void OnPreOpen()
    {
        base.OnPreOpen();
        MainWin.TabChangeEvent += OnTabChangeEvent;
        BattleManager.Instance.onBattleFieldCreate += OnCreateBattleField;
        EventBroadcast.Instance.AddListener<BattleDmgInfo>(EventName.BATTLE_DAMAGE_TAKEN, OnDamageTaken);
        EventBroadcast.Instance.AddListener<string, SkillConfig, TeamHero>(EventName.BATTLE_CAST_SKILL, OnCastSkill);
        EventBroadcast.Instance.AddListener<string, JsonData>(EventName.BATTLE_END, OnBattleEnd);
        BattleManager.Instance.storyBattleField.IsPause = true;
        bool isOpenBattleChangeTab = IsOpenBattleChangeTab();
        transButtons.localPosition = new Vector3(0, isOpenBattleChangeTab ? 130 : 0, 0);
        if (isOpenBattleChangeTab)
@@ -97,14 +62,7 @@
    protected override void OnPreClose()
    {
        base.OnPreClose();
        UIManager.Instance.CloseWindow<BattleHUDWin>();
        MainWin.TabChangeEvent -= OnTabChangeEvent;
        BattleManager.Instance.onBattleFieldCreate -= OnCreateBattleField;
        EventBroadcast.Instance.RemoveListener<BattleDmgInfo>(EventName.BATTLE_DAMAGE_TAKEN, OnDamageTaken);
        EventBroadcast.Instance.RemoveListener<string, SkillConfig, TeamHero>(EventName.BATTLE_CAST_SKILL, OnCastSkill);
        EventBroadcast.Instance.RemoveListener<string, JsonData>(EventName.BATTLE_END, OnBattleEnd);
        BattleManager.Instance.storyBattleField.IsPause = false;
        bool isOpenBattleChangeTab = IsOpenBattleChangeTab();
        if (isOpenBattleChangeTab)
        {
@@ -121,109 +79,29 @@
        UIManager.Instance.CloseWindow<ArenaBattleWin>();
    }
    private void OnBattleEnd(string guid, JsonData endData)
    protected override void OnDamageTaken(BattleDmgInfo damageInfo)
    {
        if (battleField != null && guid == battleField.guid)
        {
            DisplayHpInfo();
        }
    }
    private void OnDamageTaken(BattleDmgInfo damageInfo)
    {
        base.OnDamageTaken(damageInfo);
        if (battleField == null)
            return;
        if (damageInfo.battleFieldGuid == battleField.guid)
        {
            DisplayHpInfo();
            totalDamageDisplayer.SetDamage(damageInfo);
        }
    }
    private void OnCreateBattleField(string arg1, BattleField field)
    protected override void OnCreateBattleField(string guid, BattleField field)
    {
        if (field.GetType() == battleField.GetType())
        if (field is ArenaBattleField)
        {
            SetBattleField(field);
        }
    }
    protected override void OnClose()
    protected override void RefreshSpecific()
    {
        base.OnClose();
        if (battleRootNode != null)
        {
            battleRootNode.transform.SetParent(Launch.Instance.transform);
            battleRootNode.transform.localPosition = new Vector3(-10000, -10000, 0);
        }
        if (battleField != null)
        {
            battleField.OnRoundChange -= OnRoundChange;
            battleField = null;
        }
    }
    public void SetBattleField(BattleField _battleField)
    {
        if (battleField != null)
        {
            battleField.OnRoundChange -= OnRoundChange;
            battleField = null;
        }
        battleField = _battleField;
        if (battleRootNode != null)
        {
            battleRootNode.transform.localPosition = Vector3.zero;
            battleRootNode.transform.SetParent(Launch.Instance.transform);
        }
        battleRootNode = battleField.battleRootNode;
        battleRootNode.transform.SetParent(mountPoint);
        battleRootNode.transform.localPosition = Vector3.zero;
        battleRootNode.transform.localScale = Vector3.one;
        BattleHUDWin ui = UIManager.Instance.GetUI<BattleHUDWin>();
        if (null == ui)
        {
            ui = UIManager.Instance.OpenWindow<BattleHUDWin>();
        }
        ui.SetBattleField(battleField);
        battleField.UpdateCanvas(canvas);
        textSpeed.text = (BattleManager.Instance.speedIndex + 1).ToString();
        Refresh();
        battleField.OnRoundChange -= OnRoundChange;
        battleField.OnRoundChange += OnRoundChange;
        OnRoundChange(battleField.round, battleField.turnMax);
    }
    public override void Refresh()
    {
        base.Refresh();
        DisplayHpInfo();
        DisplayPlayerInfo();
        totalDamageDisplayer.SetActive(false);
        skillTipsBlue.SetActive(false);
        skillTipsRed.SetActive(false);
    }
    private void OnCastSkill(string guid, SkillConfig skillConfig, TeamHero teamHero)
    {
        if (battleField == null)
            return;
        if (battleField.guid != guid)
            return;
        BattleObject battleObject = battleField.battleObjMgr.GetBattleObject(teamHero.ObjID);
        bool isRed = battleObject.Camp == BattleCamp.Red;
        SkillTips tips = isRed ? skillTipsRed : skillTipsBlue;
        tips.PlayMotion(battleField, isRed, teamHero, skillConfig);
    }
    private void DisplayHpInfo()
@@ -346,13 +224,8 @@
    }
    private void OnRoundChange(int round, int maxRound)
    {
        txtWaveInfo.text = string.Format("{0}/{1}", round, maxRound);
    }
    bool IsOpenBattleChangeTab()
    {
        return FuncOpen.Instance.IsFuncOpen(ArenaManager.Instance.BattleChangeTabFuncId);
    }
}
}
Main/System/Battle/BaseBattleWin.cs
New file
@@ -0,0 +1,279 @@
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 战斗窗口基类
/// </summary>
public abstract class BaseBattleWin : UIBase
{
    [Header("战斗场景挂载点")]
    [SerializeField]
    protected Transform mountPoint;
    [Header("战斗控制按钮")]
    [SerializeField] protected Button btnSpeed; // 速度控制
    [SerializeField] protected Text textSpeed; // 速度显示
    [SerializeField] protected Button btnPass; // 跳过战斗
    [SerializeField] protected Button btnPause; // 暂停按钮 (BattleWin中的btnStop可对应此按钮)
    [Header("战斗UI组件")]
    [SerializeField] protected TotalDamageDisplayer totalDamageDisplayer; // 伤害统计
    [SerializeField] protected SkillTips skillTipsRed; // 红方技能提示
    [SerializeField] protected SkillTips skillTipsBlue; // 蓝方技能提示
    [SerializeField] protected Text txtBattleRound; // 回合信息 (Arena的txtWaveInfo, Story/Bone的txtBattleRound)
    protected BattleRootNode battleRootNode = null;
    protected BattleField battleField; // 当前战斗的战场实例
    protected override void InitComponent()
    {
        base.InitComponent();
        // 绑定通用按钮事件
        if (btnSpeed != null)
            btnSpeed.AddListener(ChangeSpeed);
        if (btnPass != null)
            btnPass.AddListener(OnClickPass);
        if (btnPause != null)
            btnPause.AddListener(OnClickPause);
    }
    protected override void OnPreOpen()
    {
        base.OnPreOpen();
        BattleManager.Instance.onBattleFieldCreate += OnCreateBattleField;
        RegisterBattleEvents();
        // 在打开时需要暂停主线战斗
        if (BattleManager.Instance.storyBattleField != null)
            BattleManager.Instance.storyBattleField.IsPause = true;
    }
    protected override void OnPreClose()
    {
        base.OnPreClose();
        UIManager.Instance.CloseWindow<BattleHUDWin>();
        BattleManager.Instance.onBattleFieldCreate -= OnCreateBattleField;
        UnregisterBattleEvents();
        // 在关闭时恢复主线战斗
        if (BattleManager.Instance.storyBattleField != null)
            BattleManager.Instance.storyBattleField.IsPause = false;
        if (battleField != null)
        {
            battleField.OnRoundChange -= OnRoundChange;
        }
    }
    protected override void OnClose()
    {
        base.OnClose();
        if (battleRootNode != null)
        {
            battleRootNode.transform.SetParent(Launch.Instance.transform);
            battleRootNode.transform.localPosition = new Vector3(-10000, -10000, 0);
        }
        battleField = null;
    }
    /// <summary>
    /// 通用刷新逻辑 (模板方法)
    /// </summary>
    public override void Refresh()
    {
        base.Refresh();
        // 1. 执行基类通用刷新逻辑 (清空旧状态)
        if (totalDamageDisplayer != null)
            totalDamageDisplayer.SetActive(false);
        if (skillTipsBlue != null)
            skillTipsBlue.SetActive(false);
        if (skillTipsRed != null)
            skillTipsRed.SetActive(false);
        // 刷新速度显示
        if (textSpeed != null && BattleManager.Instance != null)
            textSpeed.text = (BattleManager.Instance.speedIndex + 1).ToString();
        // 2. 调用子类特定的刷新逻辑
        if (battleField != null) // 确保战场存在后再调用特定刷新
        {
            RefreshSpecific();
        }
    }
    /// <summary>
    /// 子类实现的特定刷新逻辑
    /// </summary>
    protected abstract void RefreshSpecific();
    /// <summary>
    /// 当战斗字段创建时 (子类必须重写, 以匹配特定的战场类型)
    /// </summary>
    /// <param name="guid"></param>
    /// <param name="field"></param>
    protected abstract void OnCreateBattleField(string guid, BattleField field);
    // 示例:
    // protected override void OnCreateBattleField(string guid, BattleField field)
    // {
    //     // 检查是否是当前窗口关心的战场类型
    //     if (field is ArenaBattleField arenaField)
    //     {
    //         SetBattleField(arenaField); // 调用SetBattleField
    //     }
    // }
    /// <summary>
    /// 设置战斗字段
    /// </summary>
    public virtual void SetBattleField(BattleField _battleField)
    {
        // 1. 清理旧的战场
        if (battleField != null)
        {
            battleField.OnRoundChange -= OnRoundChange;
            battleField = null;
        }
        // 2. 设置新的战场
        battleField = _battleField;
        if (battleField == null) return;
        // 3. 关联战斗场景根节点
        if (battleRootNode != null) // 归还旧的
        {
            battleRootNode.transform.localPosition = Vector3.zero;
            battleRootNode.transform.SetParent(Launch.Instance.transform);
        }
        battleRootNode = battleField.battleRootNode;
        if (battleRootNode == null) return;
        battleRootNode.transform.SetParent(mountPoint); // 挂载新的
        battleRootNode.transform.localPosition = Vector3.zero;
        battleRootNode.transform.localScale = Vector3.one;
        // 4. 打开或获取HUD
        BattleHUDWin ui = UIManager.Instance.GetUI<BattleHUDWin>();
        if (null == ui)
        {
            ui = UIManager.Instance.OpenWindow<BattleHUDWin>();
        }
        ui.SetBattleField(battleField);
        // 5. 更新Canvas
        battleField.UpdateCanvas(canvas);
        // 6. 刷新UI
        Refresh();
        // 7. 监听回合变更
        battleField.OnRoundChange -= OnRoundChange;
        battleField.OnRoundChange += OnRoundChange;
        OnRoundChange(battleField.round, battleField.turnMax); // 立即执行一次以显示初始回合
    }
    /// <summary>
    /// 暂停/继续
    /// </summary>
    protected virtual void OnClickPause()
    {
        if (null == battleField)
            return;
        battleField.IsPause = !battleField.IsPause;
    }
    /// <summary>
    /// 跳过战斗
    /// </summary>
    protected virtual void OnClickPass()
    {
        if (null == battleField)
            return;
        battleField.ForceFinish();
    }
    /// <summary>
    /// 改变速度
    /// </summary>
    protected virtual void ChangeSpeed()
    {
        if (null == battleField)
            return;
        BattleManager.Instance.speedIndex = (BattleManager.Instance.speedIndex + 1) % BattleManager.Instance.speedGear.Length;
        battleField.SetSpeedRatio(BattleManager.Instance.speedGear[BattleManager.Instance.speedIndex]);
        if (textSpeed != null)
            textSpeed.text = (BattleManager.Instance.speedIndex + 1).ToString();
    }
    /// <summary>
    /// 注册战斗事件
    /// </summary>
    protected virtual void RegisterBattleEvents()
    {
        EventBroadcast.Instance.AddListener<BattleDmgInfo>(EventName.BATTLE_DAMAGE_TAKEN, OnDamageTaken);
        EventBroadcast.Instance.AddListener<string, SkillConfig, TeamHero>(EventName.BATTLE_CAST_SKILL, OnCastSkill);
    }
    /// <summary>
    /// 注销战斗事件
    /// (BattleWin 应该重写此方法并置空)
    /// </summary>
    protected virtual void UnregisterBattleEvents()
    {
        EventBroadcast.Instance.RemoveListener<BattleDmgInfo>(EventName.BATTLE_DAMAGE_TAKEN, OnDamageTaken);
        EventBroadcast.Instance.RemoveListener<string, SkillConfig, TeamHero>(EventName.BATTLE_CAST_SKILL, OnCastSkill);
    }
    /// <summary>
    /// 造成伤害
    /// </summary>
    protected virtual void OnDamageTaken(BattleDmgInfo damageInfo)
    {
        if (battleField == null || damageInfo.battleFieldGuid != battleField.guid)
            return;
        // 通用逻辑:显示伤害数字
        if (totalDamageDisplayer != null)
            totalDamageDisplayer.SetDamage(damageInfo);
    }
    /// <summary>
    /// 释放技能 (通用:显示技能Tips)
    /// </summary>
    protected virtual void OnCastSkill(string guid, SkillConfig skillConfig, TeamHero teamHero)
    {
        if (battleField == null || battleField.guid != guid)
            return;
        BattleObject battleObject = battleField.battleObjMgr.GetBattleObject(teamHero.ObjID);
        if (battleObject == null)
            return;
        bool isRed = battleObject.Camp == BattleCamp.Red;
        SkillTips tips = isRed ? skillTipsRed : skillTipsBlue;
        if (tips != null)
            tips.PlayMotion(battleField, isRed, teamHero, skillConfig);
    }
    /// <summary>
    /// 回合变更 (通用:刷新回合显示)
    /// </summary>
    protected virtual void OnRoundChange(int round, int maxRound)
    {
        if (txtBattleRound != null)
        {
            txtBattleRound.text = string.Format("{0}/{1}", round, maxRound);
        }
    }
}
Main/System/Battle/BaseBattleWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d8f186c2bc4af9b40b734d732c37322b
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/Battle/BattleDebug.cs
@@ -8,7 +8,7 @@
#if UNITY_EDITOR
        if (Launch.Instance.isOpenBattleDebug)
        {
            Debug.LogError(_logMessage);
            Debug.LogWarning("BattleLog: " + _logMessage);
        }
#endif
    }
Main/System/Battle/BattleField/StoryBattleField.cs
@@ -227,6 +227,7 @@
                        dropList.Add(item.gridIndex);
                    }
                    EquipModel.Instance.NotifyItemDrop(dropList, null);
                    BattleDebug.LogError("RequestFight: 装备未处理");
                    return false;
                }
@@ -238,6 +239,7 @@
                    {
                        HaveRest();
                    }
                    BattleDebug.LogError("RequestFight: 锤子不足");
                    return true;
                }
@@ -264,7 +266,7 @@
                }
                else
                {
                    BattleDebug.LogError("unknown battle state");
                    BattleDebug.LogError("RequestFight: unknown battle state");
                    return true;
                }
@@ -282,6 +284,7 @@
            }
            else
            {
                BattleDebug.LogError("RequestFight: 还有战斗相关包未处理完成");
            }
        }
        else
@@ -289,7 +292,7 @@
            if (!AutoFightModel.Instance.isAutoAttack)
            {
                BattleDebug.LogError("action doesnt finish, wait a moment please");
                BattleDebug.LogError("RequestFight: action doesnt finish, wait a moment please");
            }
        }
        return false;
Main/System/Battle/BoneFieldBattleWin.cs
@@ -2,72 +2,20 @@
using UnityEngine;
using UnityEngine.UI;
public class BoneFieldBattleWin : UIBase
public class BoneFieldBattleWin : BaseBattleWin
{
    [SerializeField] Transform transButtons;
    public Transform mountPoint;
    private BattleRootNode battleRootNode = null;
    private BoneBattleField battleField;
    [SerializeField] private Button btnSpeed;
    [SerializeField] private Text textSpeed;
    [SerializeField] private Button btnPass;
    [SerializeField] private Button btnPause;
    public BossLifeBar bossLifeBar;
    public SkillWordCell[] skillWordCells;
    public BossHeadCell bossHeadCell;
    public Text txtBossName;
    public Text txtBattleRound;
    public TotalDamageDisplayer totalDamageDisplayer;
    public SkillTips skillTipsRed;
    public SkillTips skillTipsBlue;
    [SerializeField] public BossLifeBar bossLifeBar;
    [SerializeField] public SkillWordCell[] skillWordCells;
    [SerializeField] public BossHeadCell bossHeadCell;
    [SerializeField] public Text txtBossName;
    private BattleObject bossBattleObject = null;
    [SerializeField] public List<BattleBuffCell> buffCells;
    // 生命周期
    protected override void InitComponent()
    {
        base.InitComponent();
        // 初始化组件引用 绑定按钮等UI组件事件
        btnSpeed.AddListener(ChangeSpeed);
        btnPass.AddListener(OnClickPass);
        btnPause.AddListener(OnClickPause);
    }
    private void OnClickPause()
    {
        if (null == battleField)
            return;
        battleField.IsPause = !battleField.IsPause;
    }
    private void OnClickPass()
    {
        if (null == battleField)
            return;
        battleField.ForceFinish();
    }
    private void ChangeSpeed()
    {
        if (null == battleField)
            return;
        BattleManager.Instance.speedIndex = (BattleManager.Instance.speedIndex + 1) % BattleManager.Instance.speedGear.Length;
        battleField.SetSpeedRatio(BattleManager.Instance.speedGear[BattleManager.Instance.speedIndex]);
        textSpeed.text = (BattleManager.Instance.speedIndex + 1).ToString();
    }
    protected override void OnPreOpen()
    {
        base.OnPreOpen();
        MainWin.TabChangeEvent += OnTabChangeEvent;
        BattleManager.Instance.onBattleFieldCreate += OnCreateBattleField;
        EventBroadcast.Instance.AddListener<BattleDmgInfo>(EventName.BATTLE_DAMAGE_TAKEN, OnDamageTaken);
        EventBroadcast.Instance.AddListener<string, SkillConfig, TeamHero>(EventName.BATTLE_CAST_SKILL, OnCastSkill);
        BattleManager.Instance.storyBattleField.IsPause = true;
        bool isOpenBattleChangeTab = IsOpenBattleChangeTab();
        transButtons.localPosition = new Vector3(0, isOpenBattleChangeTab ? 130 : 0, 0);
        if (isOpenBattleChangeTab)
@@ -80,17 +28,11 @@
        }
    }
    protected override void OnPreClose()
    {
        base.OnPreClose();
        MainWin.TabChangeEvent -= OnTabChangeEvent;
        BattleManager.Instance.onBattleFieldCreate -= OnCreateBattleField;
        EventBroadcast.Instance.RemoveListener<BattleDmgInfo>(EventName.BATTLE_DAMAGE_TAKEN, OnDamageTaken);
        EventBroadcast.Instance.RemoveListener<string, SkillConfig, TeamHero>(EventName.BATTLE_CAST_SKILL, OnCastSkill);
        UIManager.Instance.CloseWindow<BattleHUDWin>();
        BattleManager.Instance.storyBattleField.IsPause = false;
        bool isOpenBattleChangeTab = IsOpenBattleChangeTab();
        if (isOpenBattleChangeTab)
        {
@@ -110,45 +52,27 @@
            bossBattleObject = null;
        }
        if (battleField != null)
        {
            battleField.OnRoundChange -= OnRoundChange;
            battleField = null;
        }
    }
    private void OnTabChangeEvent()
    {
        UIManager.Instance.CloseWindow<BoneFieldBattleWin>();
    }
    private void OnCastSkill(string guid, SkillConfig skillConfig, TeamHero teamHero)
    protected override void OnCreateBattleField(string guid, BattleField field)
    {
        if (battleField == null)
            return;
        if (battleField.guid != guid)
            return;
        BattleObject battleObject = battleField.battleObjMgr.GetBattleObject(teamHero.ObjID);
        bool isRed = battleObject.Camp == BattleCamp.Red;
        SkillTips tips = isRed ? skillTipsRed : skillTipsBlue;
        tips.PlayMotion(battleField, isRed, teamHero, skillConfig);
    }
    private void OnCreateBattleField(string arg1, BattleField field)
    {
        if (field.GetType() == battleField.GetType())
        if (field is BoneBattleField)
        {
            SetBattleField(field as BoneBattleField);
            SetBattleField(field);
        }
    }
    public void Display()
    protected override void RefreshSpecific()
    {
        BoneBattleField boneField = battleField as BoneBattleField;
        if (boneField == null) return;
        NPCLineupConfig lineupConfig = battleField.GetBossLineupConfig();
        NPCLineupConfig lineupConfig = boneField.GetBossLineupConfig();
        if (bossBattleObject != null)
        {
@@ -159,7 +83,7 @@
            bossBattleObject = null;
        }
        bossBattleObject = battleField.FindBoss();
        bossBattleObject = boneField.FindBoss();
        DisplaySkillWordsList(lineupConfig);
@@ -181,14 +105,8 @@
            Debug.LogError("找不到boss");
        }
        OnRoundChange(battleField.round, battleField.turnMax);
        OnRoundChange(battleField.round, battleField.turnMax); // 确保回合显示被调用
        OnBuffChanged();
        totalDamageDisplayer.SetActive(false);
        skillTipsBlue.SetActive(false);
        skillTipsRed.SetActive(false);
    }
    private void OnBuffChanged()
@@ -211,76 +129,23 @@
    }
    private void OnDamageTaken(BattleDmgInfo info)
    protected override void OnDamageTaken(BattleDmgInfo info)
    {
        if (info.battleFieldGuid != battleField.guid)
        base.OnDamageTaken(info);
        if (battleField == null || info.battleFieldGuid != battleField.guid)
            return;
        if (info.hurtObj.ObjID == bossBattleObject.ObjID)
        if (bossBattleObject != null && info.hurtObj.ObjID == bossBattleObject.ObjID)
        {
            // Update the boss's health bar
            RefreshHP();
        }
        totalDamageDisplayer.SetDamage(info);
    }
    protected override void OnClose()
    {
        base.OnClose();
        if (battleRootNode != null)
        {
            battleRootNode.transform.SetParent(Launch.Instance.transform);
            battleRootNode.transform.localPosition = new Vector3(-10000, -10000, 0);
        }
        battleField = null;
    }
    protected override void NextFrameAfterOpen()
    {
        base.NextFrameAfterOpen();
    }
    protected override void CompleteClose()
    {
        base.CompleteClose();
    }
    public void SetBattleField(BoneBattleField _battleField)
    {
        if (battleField != null)
        {
            battleField.OnRoundChange -= OnRoundChange;
            battleField = null;
        }
        battleField = _battleField;
        if (battleRootNode != null)
        {
            battleRootNode.transform.localPosition = Vector3.zero;
            battleRootNode.transform.SetParent(Launch.Instance.transform);
        }
        battleRootNode = battleField.battleRootNode;
        battleRootNode.transform.SetParent(mountPoint);
        battleRootNode.transform.localPosition = Vector3.zero;
        battleRootNode.transform.localScale = Vector3.one;
        BattleHUDWin ui = UIManager.Instance.GetUI<BattleHUDWin>();
        if (null == ui)
        {
            ui = UIManager.Instance.OpenWindow<BattleHUDWin>();
        }
        ui.SetBattleField(battleField);
        battleField.UpdateCanvas(canvas);
        Display();
        battleField.OnRoundChange += OnRoundChange;
        textSpeed.text = (BattleManager.Instance.speedIndex + 1).ToString();
    }
    public void DisplaySkillWordsList(NPCLineupConfig lineUPConfig)
@@ -336,13 +201,8 @@
        }
    }
    private void OnRoundChange(int round, int maxRound)
    {
        txtBattleRound.text = string.Format("{0}/{1}", round, maxRound);
    }
    bool IsOpenBattleChangeTab()
    {
        return FuncOpen.Instance.IsFuncOpen(ArenaManager.Instance.BattleChangeTabFuncId);
    }
}
}
Main/System/Battle/StoryBossBattleWin.cs
@@ -1,112 +1,33 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class StoryBossBattleWin : UIBase
public class StoryBossBattleWin : BaseBattleWin
{
    // 组件引用
    public Transform mountPoint;
    private BattleRootNode battleRootNode = null;
    private StoryBossBattleField battleField;
    [SerializeField]
    private Button btnSpeed;
    [SerializeField]
    private Text textSpeed;
    [SerializeField]
    private Button btnPass;
    [SerializeField]
    private Button btnPause;
    public BossLifeBar bossLifeBar;
    [SerializeField]
    public SkillWordCell[] skillWordCells;
    [SerializeField]
    public BossHeadCell bossHeadCell;
    [SerializeField]
    public Text txtBossName;
    public Text txtBattleRound;
    public TotalDamageDisplayer totalDamageDisplayer;
    public SkillTips skillTipsRed;
    public SkillTips skillTipsBlue;
    private BattleObject bossBattleObject = null;
    [SerializeField] public List<BattleBuffCell> buffCells;
    // 生命周期
    protected override void InitComponent()
    {
        base.InitComponent();
        // 初始化组件引用 绑定按钮等UI组件事件
        btnSpeed.AddListener(ChangeSpeed);
        btnPass.AddListener(OnClickPass);
        btnPause.AddListener(OnClickPause);
    }
    private void OnClickPause()
    {
        if (null == battleField)
            return;
        battleField.IsPause = !battleField.IsPause;
    }
    private void OnClickPass()
    {
        if (null == battleField)
            return;
        battleField.ForceFinish();
    }
    private void ChangeSpeed()
    {
        if (null == battleField)
            return;
        BattleManager.Instance.speedIndex = (BattleManager.Instance.speedIndex + 1) % BattleManager.Instance.speedGear.Length;
        battleField.SetSpeedRatio(BattleManager.Instance.speedGear[BattleManager.Instance.speedIndex]);
        textSpeed.text = (BattleManager.Instance.speedIndex + 1).ToString();
    }
    protected override void OnPreOpen()
    {
        base.OnPreOpen();
        // SetBattleField(BattleManager.Instance.storyBattleField);
        BattleManager.Instance.onBattleFieldCreate += OnCreateBattleField;
        EventBroadcast.Instance.AddListener<BattleDmgInfo>(EventName.BATTLE_DAMAGE_TAKEN, OnDamageTaken);
        EventBroadcast.Instance.AddListener<string, SkillConfig, TeamHero>(EventName.BATTLE_CAST_SKILL, OnCastSkill);
        BattleManager.Instance.storyBattleField.IsPause = true;
        UIManager.Instance.CloseWindow<MainWin>();
    }
    protected override void OnPreClose()
    {
        base.OnPreClose();
        BattleManager.Instance.onBattleFieldCreate -= OnCreateBattleField;
        EventBroadcast.Instance.RemoveListener<BattleDmgInfo>(EventName.BATTLE_DAMAGE_TAKEN, OnDamageTaken);
        EventBroadcast.Instance.RemoveListener<string, SkillConfig, TeamHero>(EventName.BATTLE_CAST_SKILL, OnCastSkill);
        UIManager.Instance.CloseWindow<BattleHUDWin>();
        BattleManager.Instance.storyBattleField.IsPause = false;
        if (!UIManager.Instance.IsOpened<MainWin>())
            UIManager.Instance.OpenWindow<MainWin>();
@@ -115,53 +36,22 @@
            bossBattleObject.buffMgr.onBuffChanged -= OnBuffChanged;
            bossBattleObject = null;
        }
    }
        if (battleField != null)
    protected override void OnCreateBattleField(string guid, BattleField field)
    {
        if (field is StoryBossBattleField)
        {
            battleField.OnRoundChange -= OnRoundChange;
            battleField = null;
            SetBattleField(field);
        }
    }
    private void OnCastSkill(string guid, SkillConfig skillConfig, TeamHero teamHero)
    protected override void RefreshSpecific()
    {
        if (battleField == null)
            return;
        StoryBossBattleField storyBossField = battleField as StoryBossBattleField;
        if (storyBossField == null) return;
        if (battleField.guid != guid)
            return;
        BattleObject battleObject = battleField.battleObjMgr.GetBattleObject(teamHero.ObjID);
        bool isRed = battleObject.Camp == BattleCamp.Red;
        SkillTips tips = isRed ? skillTipsRed : skillTipsBlue;
        tips.PlayMotion(battleField, isRed, teamHero, skillConfig);
    }
    private void OnCreateBattleField(string arg1, BattleField field)
    {
        if (field.GetType() == battleField.GetType())
        {
            SetBattleField(field as StoryBossBattleField);
        }
    }
    protected override void OnOpen()
    {
        base.OnOpen();
    }
    public override void Refresh()
    {
        base.Refresh();
        // bossLifeBar.SetBaseInfo(battleField);
        // skillWordCells;
        NPCLineupConfig lineupConfig = battleField.GetBossLineupConfig();
        NPCLineupConfig lineupConfig = storyBossField.GetBossLineupConfig();
        if (null != bossBattleObject)
        {
@@ -169,7 +59,7 @@
            bossBattleObject = null;
        }
        bossBattleObject = battleField.FindBoss();
        bossBattleObject = storyBossField.FindBoss();
        DisplaySkillWordsList(lineupConfig);
@@ -191,14 +81,8 @@
            Debug.LogError("找不到boss");
        }
        OnRoundChange(battleField.round, battleField.turnMax);
        OnRoundChange(battleField.round, battleField.turnMax); // 确保回合显示被调用
        OnBuffChanged();
        totalDamageDisplayer.SetActive(false);
        skillTipsBlue.SetActive(false);
        skillTipsRed.SetActive(false);
    }
    private void OnBuffChanged()
@@ -220,82 +104,17 @@
        }
    }
    private void OnDamageTaken(BattleDmgInfo info)
    protected override void OnDamageTaken(BattleDmgInfo info)
    {
        if (info.battleFieldGuid != battleField.guid)
        base.OnDamageTaken(info);
        if (battleField == null || info.battleFieldGuid != battleField.guid)
            return;
        if (info.hurtObj.ObjID == bossBattleObject.ObjID)
        if (bossBattleObject != null && info.hurtObj.ObjID == bossBattleObject.ObjID)
        {
            // Update the boss's health bar
            RefreshHP();
        }
        totalDamageDisplayer.SetDamage(info);
    }
    protected override void OnClose()
    {
        base.OnClose();
        if (battleRootNode != null)
        {
            battleRootNode.transform.SetParent(Launch.Instance.transform);
            battleRootNode.transform.localPosition = new Vector3(-10000, -10000, 0);
        }
        battleField = null;
    }
    protected override void NextFrameAfterOpen()
    {
        base.NextFrameAfterOpen();
    }
    protected override void CompleteClose()
    {
        base.CompleteClose();
    }
    public void SetBattleField(StoryBossBattleField _battleField)
    {
        if (battleField != null)
        {
            battleField.OnRoundChange -= OnRoundChange;
            battleField = null;
        }
        battleField = _battleField;
        if (battleRootNode != null)
        {
            battleRootNode.transform.localPosition = Vector3.zero;
            battleRootNode.transform.SetParent(Launch.Instance.transform);
        }
        battleRootNode = battleField.battleRootNode;
        battleRootNode.transform.SetParent(mountPoint);
        battleRootNode.transform.localPosition = Vector3.zero;
        battleRootNode.transform.localScale = Vector3.one;
        BattleHUDWin ui = UIManager.Instance.GetUI<BattleHUDWin>();
        if (null == ui)
        {
            ui = UIManager.Instance.OpenWindow<BattleHUDWin>();
        }
        ui.SetBattleField(battleField);
        battleField.UpdateCanvas(canvas);
        Refresh();
        battleField.OnRoundChange -= OnRoundChange;
        battleField.OnRoundChange += OnRoundChange;
        textSpeed.text = (BattleManager.Instance.speedIndex + 1).ToString();
    }
    public void DisplaySkillWordsList(NPCLineupConfig lineUPConfig)
    {
@@ -350,8 +169,4 @@
        }
    }
    private void OnRoundChange(int round, int maxRound)
    {
        txtBattleRound.text = string.Format("{0}/{1}", round, maxRound);
    }
}
}
Main/System/BillboardRank/RankModel.cs
@@ -73,7 +73,7 @@
        data.value2 = serverData.Value2;
        data.value3 = serverData.Value3;
        data.value4 = serverData.Value4;
        data.value5 = serverData.Value5;
        data.value5 = 5200050;//serverData.Value5; 这里临时用实际传的是形象ID再获得皮肤ID
        data.value6 = serverData.Value6;
        data.value7 = serverData.Value7;
        data.value8 = serverData.Value8;
@@ -170,7 +170,7 @@
        data.value2 = serverData.Value2;
        data.value3 = serverData.Value3;
        data.value4 = serverData.Value4;
        data.value5 = serverData.Value5;
        data.value5 = 5200050;//serverData.Value5; 这里临时用实际传的是形象ID再获得皮肤ID
        data.value6 = serverData.Value6;
        data.value7 = serverData.Value7;
        data.value8 = serverData.Value8;
Main/System/ChallengeTab/ArenaTabHandler.cs
New file
@@ -0,0 +1,65 @@
using System;
using UnityEngine;
public class ArenaTabHandler : BaseChallengeTabHandler
{
    protected override int GetIndex() => 1;
    protected override int GetOpenState() => 0; // 0=FuncID
    protected override int GetFuncId() => ArenaManager.Instance.funcId;
    protected override int GetRedpointId() => MainRedDot.ArenaRepoint;
    protected override string GetCountInfo()
    {
        long nowCount = UIHelper.GetMoneyCnt(ArenaManager.Instance.ChallengeMoneyType);
        return UIHelper.AppendColor(nowCount > 0 ? TextColType.Green : TextColType.Red, Language.Get("Challenge03", nowCount));
    }
    protected override Action GetOnClickAction()
    {
        return HandleArenaNavigation;
    }
    private void HandleArenaNavigation()
    {
        if (!FuncOpen.Instance.IsFuncOpen(GetFuncId(), true))
            return;
        BattleField arenaBattle = BattleManager.Instance.GetBattleFieldByMapID(3);
        if (arenaBattle != null)
        {
            ArenaBattleWin battleWin;
            if (!UIManager.Instance.IsOpened<ArenaBattleWin>())
            {
                battleWin = UIManager.Instance.OpenWindow<ArenaBattleWin>();
            }
            else
            {
                battleWin = UIManager.Instance.GetUI<ArenaBattleWin>();
            }
            battleWin.SetBattleField(arenaBattle);
        }
        else
        {
            UIManager.Instance.OpenWindow<ArenaWin>();
        }
    }
    protected override void SubscribeToSpecificEvents()
    {
        PlayerDatas.Instance.playerDataRefreshEvent += OnPlayerDataRefresh;
    }
    protected override void UnsubscribeFromSpecificEvents()
    {
        PlayerDatas.Instance.playerDataRefreshEvent -= OnPlayerDataRefresh;
    }
    private void OnPlayerDataRefresh(PlayerDataType type)
    {
        if (type == PlayerDataType.ChallengeVoucher)
        {
            Refresh();
        }
    }
}
Main/System/ChallengeTab/ArenaTabHandler.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e08213d7902819944bd303758458714a
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/ChallengeTab/BaseChallengeTabHandler.cs
New file
@@ -0,0 +1,108 @@
using System;
using UnityEngine;
/// <summary>
/// 挑战标签页按钮的逻辑处理基类
/// 挂在与 ChallengeTabButton 同一个GameObject上
/// </summary>
[RequireComponent(typeof(ChallengeTabButton))]
public abstract class BaseChallengeTabHandler : MonoBehaviour
{
    protected ChallengeTabButton tabButton;
    private ChallengeTabButton.DisplayData displayData;
    protected virtual void Awake()
    {
        tabButton = GetComponent<ChallengeTabButton>();
        // 初始化一次 DisplayData,之后只修改变化的字段
        displayData = new ChallengeTabButton.DisplayData
        {
            Index = GetIndex(),
            RedpointId = GetRedpointId(),
            OpenState = GetOpenState(),
            FuncId = GetFuncId(),
            OnClickAction = GetOnClickAction()
        };
    }
    /// <summary>
    /// 订阅事件 (由 ChallengeTabWin 在 OnPreOpen 时调用)
    /// </summary>
    public virtual void SubscribeEvents()
    {
        // 订阅全局刷新事件
        TimeMgr.Instance.OnDayEvent += Refresh;
        FuncOpen.Instance.OnFuncStateChangeEvent += OnFuncStateChange;
        // 订阅此按钮特定的事件
        SubscribeToSpecificEvents();
    }
    /// <summary>
    /// 取消订阅事件 (由 ChallengeTabWin 在 OnPreClose 时调用)
    /// </summary>
    public virtual void UnsubscribeEvents()
    {
        TimeMgr.Instance.OnDayEvent -= Refresh;
        FuncOpen.Instance.OnFuncStateChangeEvent -= OnFuncStateChange;
        UnsubscribeFromSpecificEvents();
    }
    /// <summary>
    /// 刷新UI显示 (由 ChallengeTabWin 或事件回调调用)
    /// </summary>
    public void Refresh()
    {
        if (tabButton == null)
            return;
        displayData.CountInfo = GetCountInfo();
        tabButton.Display(displayData);
    }
    private void OnFuncStateChange(int funcId)
    {
        if (GetOpenState() == 0 && funcId == GetFuncId())
        {
            Refresh();
        }
    }
    /// <summary>
    /// 获取Tab的索引(用于Icon和Name)
    /// </summary>
    protected abstract int GetIndex();
    /// <summary>
    /// 获取开启方式 (0=FuncID, 1=活动)
    /// </summary>
    protected abstract int GetOpenState();
    /// <summary>
    /// 获取功能ID
    /// </summary>
    protected abstract int GetFuncId();
    /// <summary>
    /// 获取红点ID
    /// </summary>
    protected abstract int GetRedpointId();
    /// <summary>
    /// 获取数量的显示文本
    /// </summary>
    protected abstract string GetCountInfo();
    /// <summary>
    /// 获取按钮点击时触发的 *具体* 业务逻辑
    /// </summary>
    protected abstract Action GetOnClickAction();
    /// <summary>
    /// 订阅此Tab特有的事件
    /// </summary>
    protected abstract void SubscribeToSpecificEvents();
    /// <summary>
    /// 取消订阅此Tab特有的事件
    /// </summary>
    protected abstract void UnsubscribeFromSpecificEvents();
}
Main/System/ChallengeTab/BaseChallengeTabHandler.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 91477a81b5997714db36457077d03ac4
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/ChallengeTab/BoneFieldTabHandler.cs
New file
@@ -0,0 +1,78 @@
using System;
using UnityEngine;
public class BoneFieldTabHandler : BaseChallengeTabHandler
{
    protected override int GetIndex() => 2;
    protected override int GetOpenState() => 0; // 0=FuncID
    protected override int GetFuncId() => BoneFieldManager.Instance.funcId;
    protected override int GetRedpointId() => MainRedDot.BoneFieldRepoint;
    protected override string GetCountInfo()
    {
        if (BoneFieldManager.Instance.TryGetShowSweepCount(out int _, out int showrealRemainSweepCount))
        {
            return UIHelper.AppendColor(showrealRemainSweepCount > 0 ? TextColType.Green : TextColType.Red, Language.Get("Challenge01", showrealRemainSweepCount));
        }
        return string.Empty; // 获取失败时返回空
    }
    protected override Action GetOnClickAction()
    {
        return HandleBoneFieldNavigation;
    }
    private void HandleBoneFieldNavigation()
    {
        if (!FuncOpen.Instance.IsFuncOpen(GetFuncId(), true))
            return;
        BattleField battleField = BattleManager.Instance.GetBattleFieldByMapID(30010);
        if (battleField != null)
        {
            BoneFieldBattleWin battleWin;
            if (!UIManager.Instance.IsOpened<BoneFieldBattleWin>())
            {
                battleWin = UIManager.Instance.OpenWindow<BoneFieldBattleWin>();
            }
            else
            {
                battleWin = UIManager.Instance.GetUI<BoneFieldBattleWin>();
            }
            battleWin.SetBattleField(battleField as BoneBattleField);
        }
        else
        {
            UIManager.Instance.OpenWindow<BoneFieldWin>();
        }
    }
    protected override void SubscribeToSpecificEvents()
    {
        DungeonManager.Instance.UpdateFBInfoChangeEvent += OnUpdateFBInfoChange;
        AdsManager.Instance.OnAdsInfoListUpdateEvent += OnAdsInfoListUpdate;
    }
    protected override void UnsubscribeFromSpecificEvents()
    {
        DungeonManager.Instance.UpdateFBInfoChangeEvent -= OnUpdateFBInfoChange;
        AdsManager.Instance.OnAdsInfoListUpdateEvent -= OnAdsInfoListUpdate;
    }
    private void OnUpdateFBInfoChange(int mapID, bool isADAddCntChange, bool isBuyAddCntChange, bool isItemAddCntChange)
    {
        if (mapID == BoneFieldManager.Instance.DataMapID)
        {
            Refresh();
        }
    }
    private void OnAdsInfoListUpdate(int adID, int mapID)
    {
        if (mapID == BoneFieldManager.Instance.DataMapID)
        {
            Refresh();
        }
    }
}
Main/System/ChallengeTab/BoneFieldTabHandler.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bc6f3e382ad10c048af48f137e2f9569
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/ChallengeTab/ChallengeTabButton.cs
@@ -11,31 +11,73 @@
    [SerializeField] TextEx txtLockInfo;
    [SerializeField] Transform transUnlock;
    [SerializeField] RedpointBehaviour redpointBehaviour;
    Action action;
    void Awake()
    private Action _onClickAction;
    public struct DisplayData
    {
        btnTab.SetListener(() =>
        {
            UIManager.Instance.CloseWindow<ChallengeTabWin>();
            string activeBattleName = BattleManager.Instance.GetActiveBattleName();
            if (activeBattleName != "" && activeBattleName != "StoryBattleField")
            {
                UIManager.Instance.GetUI<MainWin>().ClickFunc(0);
            }
            action?.Invoke();
        });
        public int Index;
        public int RedpointId;
        public int OpenState;//0 FuncID 1 活动
        public int FuncId;
        public string CountInfo;
        public Action OnClickAction; // 按钮点击时触发的具体逻辑
    }
    public void Display(int index, int redpointId, bool isLock, string countInfo, string lockInfo, Action action)
    void Awake()
    {
        redpointBehaviour.redpointId = redpointId;
        transUnlock.SetActive(!isLock);
        txtCount.SetActive(isLock);
        txtLockInfo.SetActive(!isLock);
        imgIcon.SetSprite(StringUtility.Contact("ChallengeTab", index));
        txtName.text = Language.Get(StringUtility.Contact("ChallengeTab", index));
        txtCount.text = countInfo;
        txtLockInfo.text = lockInfo;
        this.action = action;
        btnTab.SetListener(OnTabClicked);
    }
}
    /// <summary>
    /// 处理按钮点击事件
    /// </summary>
    private void OnTabClicked()
    {
        // --- 通用点击逻辑 ---
        UIManager.Instance.CloseWindow<ChallengeTabWin>();
        string activeBattleName = BattleManager.Instance.GetActiveBattleName();
        if (activeBattleName != "" && activeBattleName != "StoryBattleField")
        {
            UIManager.Instance.GetUI<MainWin>().ClickFunc(0);
        }
        // 执行传入的具体业务逻辑
        _onClickAction?.Invoke();
    }
    /// <summary>
    /// 使用 DisplayData 结构体来更新按钮显示
    /// </summary>
    /// <param name="data">包含所有显示和行为配置的数据</param>
    public void Display(DisplayData data)
    {
        redpointBehaviour.redpointId = data.RedpointId;
        bool isOpen;
        if (data.OpenState == 0)
        {
            isOpen = FuncOpen.Instance.IsFuncOpen(data.FuncId);
        }
        else
        {
            isOpen = false;
        }
        // 根据锁定状态设置显隐
        transUnlock.SetActive(!isOpen);
        txtCount.SetActive(isOpen);
        txtLockInfo.SetActive(!isOpen);
        // 设置图标和名称
        string spriteAndLangKey = StringUtility.Contact("ChallengeTab", data.Index);
        imgIcon.SetSprite(spriteAndLangKey);
        txtName.text = Language.Get(spriteAndLangKey);
        // 设置TIPS文本
        txtCount.text = data.CountInfo;
        txtLockInfo.text = !isOpen ? Language.Get("Challenge02") : string.Empty;
        // 存储点击回调
        this._onClickAction = data.OnClickAction;
    }
}
Main/System/ChallengeTab/ChallengeTabWin.cs
@@ -3,146 +3,42 @@
public class ChallengeTabWin : UIBase
{
    [SerializeField] ChallengeTabButton btnBoneField;
    [SerializeField] ChallengeTabButton btnArena;
    private BaseChallengeTabHandler[] tabHandlers;
    protected override void InitComponent()
    {
        base.InitComponent();
        // 自动查找所有子对象上的 Handler 组件
        tabHandlers = GetComponentsInChildren<BaseChallengeTabHandler>(true);
    }
    protected override void OnPreOpen()
    {
        base.OnPreOpen();
        DungeonManager.Instance.UpdateFBInfoChangeEvent += OnUpdateFBInfoChangeEvent;
        AdsManager.Instance.OnAdsInfoListUpdateEvent += OnAdsInfoListUpdateEvent;
        TimeMgr.Instance.OnDayEvent += OnDayEvent;
        FuncOpen.Instance.OnFuncStateChangeEvent += OnFuncStateChangeEvent;
        PlayerDatas.Instance.playerDataRefreshEvent += PlayerDataRefresh;
        foreach (var handler in tabHandlers)
        {
            handler.SubscribeEvents();
        }
        Display();
    }
    protected override void OnPreClose()
    {
        base.OnPreClose();
        DungeonManager.Instance.UpdateFBInfoChangeEvent -= OnUpdateFBInfoChangeEvent;
        AdsManager.Instance.OnAdsInfoListUpdateEvent -= OnAdsInfoListUpdateEvent;
        TimeMgr.Instance.OnDayEvent -= OnDayEvent;
        FuncOpen.Instance.OnFuncStateChangeEvent -= OnFuncStateChangeEvent;
        PlayerDatas.Instance.playerDataRefreshEvent -= PlayerDataRefresh;
        foreach (var handler in tabHandlers)
        {
            handler.UnsubscribeEvents();
        }
        UIManager.Instance.GetUI<MainWin>()?.RestoreFuncBtn();
    }
    private void OnDayEvent()
    {
        Display();
    }
    private void OnAdsInfoListUpdateEvent(int id, int mapId)
    {
        Display();
    }
    private void OnUpdateFBInfoChangeEvent(int arg1, bool arg2, bool arg3, bool arg4)
    {
        if (arg1 == BoneFieldManager.Instance.DataMapID)
        {
            DisplayBoneFieldButton();
        }
    }
    public void OnFuncStateChangeEvent(int funcId)
    {
        if (funcId == BoneFieldManager.Instance.funcId)
        {
            DisplayBoneFieldButton();
        }
        else if (funcId == ArenaManager.Instance.funcId)
        {
            DisplayArenaButton();
        }
    }
    private void PlayerDataRefresh(PlayerDataType type)
    {
        if (type == PlayerDataType.ChallengeVoucher)
        {
            DisplayArenaButton();
        }
    }
    public void Display()
    {
        DisplayBoneFieldButton();
        DisplayArenaButton();
    }
    public void DisplayArenaButton()
    {
        int index = 1;
        int funcId = ArenaManager.Instance.funcId;
        int redpointId = MainRedDot.ArenaRepoint;
        bool isLock = FuncOpen.Instance.IsFuncOpen(funcId);
        int type = ArenaManager.Instance.ChallengeMoneyType;
        long nowCount = UIHelper.GetMoneyCnt(type);
        string countInfo = UIHelper.AppendColor(nowCount > 0 ? TextColType.Green : TextColType.Red, Language.Get("Challenge03", nowCount));
        string lockInfo = !isLock ? Language.Get("Challenge02") : string.Empty;
        btnArena.Display(index, redpointId, isLock, countInfo, lockInfo, () =>
        {
            if (!FuncOpen.Instance.IsFuncOpen(funcId, true))
                return;
            BattleField arenaBattle = BattleManager.Instance.GetBattleFieldByMapID(3);
            if (arenaBattle != null)
            {
                ArenaBattleWin battleWin;
                if (!UIManager.Instance.IsOpened<ArenaBattleWin>())
                {
                    battleWin = UIManager.Instance.OpenWindow<ArenaBattleWin>();
                }
                else
                {
                    battleWin = UIManager.Instance.GetUI<ArenaBattleWin>();
                }
                battleWin.SetBattleField(arenaBattle);
            }
            else
            {
                UIManager.Instance.OpenWindow<ArenaWin>();
            }
        });
    }
    public void DisplayBoneFieldButton()
    {
        int index = 2;
        int funcId = BoneFieldManager.Instance.funcId;
        int redpointId = MainRedDot.BoneFieldRepoint;
        bool isLock = FuncOpen.Instance.IsFuncOpen(funcId);
        if (!BoneFieldManager.Instance.TryGetShowSweepCount(out int showSweepMaxCount, out int showrealRemainSweepCount))
        if (tabHandlers == null)
            return;
        string countInfo = UIHelper.AppendColor(showrealRemainSweepCount > 0 ? TextColType.Green : TextColType.Red, Language.Get("Challenge01", showrealRemainSweepCount));
        string lockInfo = !isLock ? Language.Get("Challenge02") : string.Empty;
        btnBoneField.Display(index, redpointId, isLock, countInfo, lockInfo, () =>
        foreach (var handler in tabHandlers)
        {
            if (!FuncOpen.Instance.IsFuncOpen(funcId, true))
                return;
            BattleField battleField = BattleManager.Instance.GetBattleFieldByMapID(30010);
            if (battleField != null)
            {
                BoneFieldBattleWin battleWin;
                if (!UIManager.Instance.IsOpened<BoneFieldBattleWin>())
                {
                    battleWin = UIManager.Instance.OpenWindow<BoneFieldBattleWin>();
                }
                else
                {
                    battleWin = UIManager.Instance.GetUI<BoneFieldBattleWin>();
                }
                battleWin.SetBattleField(battleField as BoneBattleField);
            }
            else
            {
                UIManager.Instance.OpenWindow<BoneFieldWin>();
            }
        });
            handler.Refresh();
        }
    }
}
}
Main/System/NewBieGuidance/NewBieWin.cs
@@ -61,8 +61,9 @@
        m_ClickTarget = null;
        tryGuideCount = 0;
        //关闭其他可能在主界面显示的窗口等
        UIManager.Instance.CloseWindow<ChatWin>();
        // UIManager.Instance.CloseWindow<ChatWin>();
        NewBieCenter.Instance.guideStepChangeEvent += OnStepChange;
        Display();
    }
    protected override void OnClose()
@@ -77,10 +78,10 @@
    }
    protected override void NextFrameAfterOpen()
    {
        Display();
    }
    // protected override void NextFrameAfterOpen()
    // {
    //     Display();
    // }
    #endregion
    void Display()
@@ -100,6 +101,10 @@
            return;
        }
        if (config.WinName != "EquipExchangeWin" && UIManager.Instance.IsOpened<EquipExchangeWin>())
        {
            UIManager.Instance.CloseWindow<EquipExchangeWin>();
        }
        try
        {
@@ -121,7 +126,7 @@
                    ReportStepOver();
                    tryGuideCount = 0;
                    return;
                }
                DelayDisplay().Forget();
                return;