yyl
10 天以前 c6a7ac3739907e8bb7c751d408e227e19f246f49
Merge remote-tracking branch 'origin/master' into h5version

# Conflicts:
# Main/Config/ConfigManager.cs
# Main/System/Arena/ArenaBattleFailWin.cs
# Main/System/Arena/ArenaBattleVictoryWin.cs
# Main/System/Arena/ArenaChallengeCell.cs
# Main/System/Arena/ArenaPlayerRankCell.cs
# Main/System/Arena/ArenaPlayerTop3Cell.cs
# Main/System/Arena/ArenaRecordCell.cs
# Main/System/Arena/ArenaWin.cs
# Main/System/Horse/HorseController.cs
51个文件已修改
87个文件已添加
6218 ■■■■■ 已修改文件
Main/Config/ConfigBase.cs 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/ConfigManager.cs 369 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/ADAwardConfig.cs 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/ActSignConfig.cs 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/ActSignConfig.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/ActSpecialSaleConfig.cs 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/ActSpecialSaleConfig.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/ActTaskConfig.cs 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/ActTaskConfig.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/ActTaskTempConfig.cs 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/ActTaskTempConfig.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/HorseSkinConfig.cs 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/RobotConfig.cs 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/RobotConfig.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/PartialConfigs/ActTaskTempConfig.cs 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/PartialConfigs/ActTaskTempConfig.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA10_tagSCActSpecialSaleInfo.cs 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA10_tagSCActSpecialSaleInfo.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA1A_tagSCActTotDayRechargePlayerInfo.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA1C_tagSCActTotalRechargePlayerInfo.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA23_tagSCActSignInfo.cs 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA23_tagSCActSignInfo.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA71_tagSCActTaskInfo.cs 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA71_tagSCActTaskInfo.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA72_tagSCActTaskPlayerValueInfo.cs 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA72_tagSCActTaskPlayerValueInfo.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA73_tagSCActTaskPlayerInfo.cs 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA73_tagSCActTaskPlayerInfo.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DataToCtl/PackageRegedit.cs 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/ServerPack/HA9_Function/HA922_tagSCArenaMatchList.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/ServerPack/HAA_SaleActivity/HAA10_tagSCActSpecialSaleInfo.cs 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/ServerPack/HAA_SaleActivity/HAA10_tagSCActSpecialSaleInfo.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/ServerPack/HAA_SaleActivity/HAA23_tagSCActSignInfo.cs 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/ServerPack/HAA_SaleActivity/HAA23_tagSCActSignInfo.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/ServerPack/HAA_SaleActivity/HAA71_tagSCActTaskInfo.cs 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/ServerPack/HAA_SaleActivity/HAA71_tagSCActTaskInfo.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/ServerPack/HAA_SaleActivity/HAA72_tagSCActTaskPlayerValueInfo.cs 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/ServerPack/HAA_SaleActivity/HAA72_tagSCActTaskPlayerValueInfo.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/ServerPack/HAA_SaleActivity/HAA73_tagSCActTaskPlayerInfo.cs 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/ServerPack/HAA_SaleActivity/HAA73_tagSCActTaskPlayerInfo.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Main.cs 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Arena/ArenaBattleFailWin.cs 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Arena/ArenaBattleVictoryWin.cs 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Arena/ArenaChallengeCell.cs 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Arena/ArenaCrossAwardCell.cs 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Arena/ArenaCrossAwardCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Arena/ArenaCrossAwardWin.cs 192 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Arena/ArenaCrossAwardWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Arena/ArenaManager.cs 202 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Arena/ArenaPlayerRankCell.cs 43 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Arena/ArenaPlayerTop3Cell.cs 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Arena/ArenaRecordCell.cs 50 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Arena/ArenaWin.cs 233 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/BillboardRank/PlayerRankCell.cs 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/BillboardRank/PlayerTop3Cell.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/BillboardRank/RankModel.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/BoneField/AdsManager.cs 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/CrossServer/CrossServerBaseManager.cs 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity.meta 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityCheckInCell.cs 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityCheckInCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityCheckInManager.cs 191 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityCheckInManager.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityCheckInWin.cs 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityCheckInWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityGiftCell.cs 227 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityGiftCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityGiftWin.cs 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityGiftWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityManager.cs 451 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityManager.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityMissionCell.cs 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityMissionCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityMissionManager.cs 471 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityMissionManager.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityMissionWin.cs 157 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityMissionWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityPopCell.cs 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityPopCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityPopWin.cs 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityPopWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityRechargeBaseWin.cs 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityRechargeBaseWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityRechargeTotDayCell.cs 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityRechargeTotDayCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityRechargeTotDayManager.cs 248 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityRechargeTotDayManager.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityRechargeTotDayWin.cs 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityRechargeTotDayWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityRechargeTotalCell.cs 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityRechargeTotalCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityRechargeTotalManager.cs 249 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityRechargeTotalManager.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityRechargeTotalWin.cs 118 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityRechargeTotalWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityShopCell.cs 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityShopCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityShopLineCell.cs 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityShopLineCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityShopWin.cs 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityShopWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityWin.cs 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/OperationCheckInActivityInfo.cs 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/OperationCheckInActivityInfo.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/OperationFlashSaleActivityInfo.cs 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/OperationFlashSaleActivityInfo.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/OperationMissionActivityInfo.cs 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/OperationMissionActivityInfo.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroDebut/HeroDebutCallRateItem.cs 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallRateItem.cs 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnZhanLingWin.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Horse/HorseController.cs 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Horse/HorseSkinWin.cs 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Login/ServerData.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Login/ServerListCenter.cs 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Main/FightPowerManager.cs 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Main/HomeWin.cs 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/OSActivity/OSActivityManager.cs 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/OpenServerActivity/OperationTimeHepler.cs 227 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/OtherPlayerDetail/OtherPlayerDetailManager.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/OtherPlayerDetail/OtherPlayerDetailWin.cs 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/PhantasmPavilion/AvatarHelper.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/PhantasmPavilion/PhantasmPavilionManager.DefaultID.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/PhantasmPavilion/PhantasmPavilionManager.cs 124 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/PhantasmPavilion/PhantasmPavilionUnlockButton.cs 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Qunying/QYBattleFailWin.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Qunying/QYBattleVictoryWin.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Qunying/QYBattleWin.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Qunying/QYFighterCell.cs 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Qunying/QYNoteCell.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Qunying/QYPlayerTop3Cell.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Qunying/QYWin.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Qunying/QunyingManager.cs 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Redpoint/MainRedDot.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Settlement/BattleSettlementManager.cs 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Utility/EnumHelper.cs 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Utility/UIHelper.cs 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/ConfigBase.cs
@@ -83,10 +83,16 @@
        for (int i = 3; i < lines.Length; i++)
        {
            string line = lines[i];
            // 跳过空行
            if (string.IsNullOrEmpty(line))
                continue;
            var index = line.IndexOf("\t");
            if (index == -1)
            {
                continue;
                string result = line.Trim();
                index = result.Length;
            }
            string strKey = line.Substring(0, index);
Main/Config/ConfigManager.cs
@@ -17,16 +17,12 @@
        private set;
    }
    private List<Type> preInitConfig = new List<Type>()
    {
      typeof (FuncConfigConfig),
    };
    private float loadingProgress = 0f;
    public override async UniTask Init()
    public override void Init()
    {
        await InitConfigs();
        base.Init();
        InitConfigs();
    }
    public virtual async UniTask InitConfigs()
@@ -35,25 +31,12 @@
        await LoadConfigs();
    }
    public async UniTask PreInit()
    {
        List<UniTask> uniTasks = new List<UniTask>();
        foreach (var type in preInitConfig)
        {
            uniTasks.Add(LoadConfigByTypeAsync(type));
        }
        await UniTask.WhenAll(uniTasks);
    }
    protected async UniTask LoadConfigs()
    {
        loadingProgress = 0f;
        isLoadFinished = false;
        // 自动生成:收集所有配置类型(此段将被 ConfigGenerater.Generate 自动覆盖)
        // 自动生成:收集所有配置类型
        // 自动生成:收集所有配置类型
        // 自动生成:收集所有配置类型
        // 加载配置文件
        HashSet<Type> configTypes = new HashSet<Type>() {
            typeof(ActBillboardAwardConfig),
            typeof(ActHeroAppearArtConfig),
@@ -62,47 +45,33 @@
            typeof(ActHeroReturnArtConfig),
            typeof(ActLunhuidianTypeConfig),
            typeof(ActSignAwardConfig),
            typeof(ActSignConfig),
            typeof(ActSpecialSaleConfig),
            typeof(ActTaskConfig),
            typeof(ActTaskTempConfig),
            typeof(ActTotalRechargeConfig),
            typeof(ActTotalRechargeTempConfig),
            typeof(ActTotDayRechargeConfig),
            typeof(ActTotDayRechargeTempConfig),
            typeof(ADAwardConfig),
            typeof(AppointItemConfig),
            typeof(AudioConfig),
            typeof(BattleMapConfig),
            typeof(BeautyConfig),
            typeof(BeautyQualityLVConfig),
            typeof(BeautySkinConfig),
            typeof(ChatBubbleBoxConfig),
            typeof(ChestsAwardConfig),
            typeof(ChestsConfig),
            typeof(CTGConfig),
            typeof(CTGSelectItemConfig),
            typeof(DailyLivenessRewardConfig),
            typeof(DailyTaskConfig),
            typeof(DamageNumConfig),
            typeof(DirtyNameConfig),
            typeof(DirtyWordConfig),
            typeof(DungeonConfig),
            typeof(DungeonOpenTimeConfig),
            typeof(EffectConfig),
            typeof(EmojiPackConfig),
            typeof(FaceConfig),
            typeof(FamilyConfig),
            typeof(FamilyDonateConfig),
            typeof(FamilyEmblemConfig),
            typeof(FBDJGEffectConfig),
            typeof(FBDJGLevelConfig),
            typeof(FBDJGQuickConfig),
            typeof(FightPowerRatioConfig),
            typeof(FirstChargeConfig),
            typeof(FirstGoldConfig),
            typeof(FrameAnimationConfig),
            typeof(FuncConfigConfig),
            typeof(FuncOpenLVConfig),
            typeof(FunctionTeamSetConfig),
            typeof(GetItemWaysConfig),
            typeof(GmCmdConfig),
            typeof(GoldRushCampConfig),
            typeof(GoldRushItemConfig),
            typeof(GoldRushWorkerConfig),
@@ -112,32 +81,18 @@
            typeof(GubaoResonanceAttrConfig),
            typeof(GubaoResonanceConfig),
            typeof(GubaoStarConfig),
            typeof(GuideConfig),
            typeof(HeroAwakeConfig),
            typeof(HeroBreakConfig),
            typeof(HeroConfig),
            typeof(HeroFatesConfig),
            typeof(HeroFatesQualityLVConfig),
            typeof(HeroFetterConfig),
            typeof(HeroLineupHaloConfig),
            typeof(HeroQualityAwakeConfig),
            typeof(HeroQualityBreakConfig),
            typeof(HeroQualityConfig),
            typeof(HeroQualityLVConfig),
            typeof(HeroSkinAttrConfig),
            typeof(HeroSkinConfig),
            typeof(HeroTalentConfig),
            typeof(HorseClassConfig),
            typeof(HorseIDConfig),
            typeof(HorseSkinConfig),
            typeof(IconConfig),
            typeof(ItemCompoundConfig),
            typeof(ItemConfig),
            typeof(KickOutReasonConfig),
            typeof(LanguageConfig),
            typeof(LineupRecommendConfig),
            typeof(LLMJConfig),
            typeof(MailConfig),
            typeof(MainChapterConfig),
            typeof(MainLevelConfig),
            typeof(MGGanwuLVConfig),
@@ -152,24 +107,16 @@
            typeof(OrderInfoConfig),
            typeof(PlayerAttrConfig),
            typeof(PlayerFaceConfig),
            typeof(PlayerFacePicConfig),
            typeof(PlayerLVConfig),
            typeof(PlayerPropertyConfig),
            typeof(PopWinOrderConfig),
            typeof(PresetUnlockConfig),
            typeof(PriorBundleConfig),
            typeof(RandomNameConfig),
            typeof(RealmConfig),
            typeof(RealmLVUPTaskConfig),
            typeof(RichTextMsgReplaceConfig),
            typeof(RuleConfig),
            typeof(RobotConfig),
            typeof(SignInConfig),
            typeof(SkillConfig),
            typeof(SkillSkinConfig),
            typeof(StoreConfig),
            typeof(SuccessConfig),
            typeof(SysInfoConfig),
            typeof(TaskConfig),
            typeof(TianziConfig),
            typeof(TimingGiftConfig),
            typeof(TimingGiftTypeConfig),
@@ -177,8 +124,6 @@
            typeof(TitleStarUpConfig),
            typeof(TravelEventConfig),
            typeof(TravelSceneryConfig),
            typeof(TreasureCntAwardConfig),
            typeof(TreasureItemLibConfig),
            typeof(TreasureSetConfig),
            typeof(TreeLVConfig),
            typeof(WindowSearchConfig),
@@ -186,85 +131,64 @@
            typeof(ZhanlingConfig)
        };
#if UNITY_EDITOR
        HashSet<Type> configHashSet = new HashSet<Type>();
        if (System.IO.File.Exists(Application.dataPath + "/fastConfig.txt") && Launch.Instance.isOpenConfigTesting)
        {
            string[] strConfgsArr = System.IO.File.ReadAllLines(Application.dataPath + "/fastConfig.txt");
            foreach (string str in strConfgsArr)
            {
                Type tpy = Type.GetType(str);
                configHashSet.Add(tpy);
            }
        }
        //  编辑器下加入 评估加载时常
        foreach (var config in configHashSet)
        {
            if (!configTypes.Add(config))
            {
                Debug.LogWarning($"配置 {config.Name} 已经存在于 configTypes 中,跳过添加。");
            }
        }
        List<string> fastName = new List<string>();
#endif
        int iterator = 0;
        int totalConfigs = configTypes.Count;
#if UNITY_WEBGL && !UNITY_EDITOR
        // ============================================================
        // WebGL 优化:两阶段加载
        // 阶段1: 一次性并发发起所有 TextAsset 加载(同 bundle 只下载一次)
        // 阶段2: 从内存中分批解析,每批 Yield 防止浏览器卡死
        // ============================================================
        // 阶段1: 并发加载所有配置文本到内存
        Debug.Log("[ConfigManager] WebGL 阶段1: 批量加载配置文件...");
        var configList = configTypes.ToList();
        var configDataMap = new Dictionary<Type, string[]>(totalConfigs);
        var loadTasks = new List<UniTask>(totalConfigs);
        foreach (var configType in configList)
        {
            var ct = configType; // closure capture
            loadTasks.Add(LoadConfigTextAsync(ct).ContinueWith(texts =>
            {
                if (texts != null)
                    configDataMap[ct] = texts;
                else
                    Debug.LogError($"找不到配置文件: {ct.Name}");
            }));
        }
        await UniTask.WhenAll(loadTasks);
        loadingProgress = 0.5f; // 网络加载完成 50%
        Debug.Log($"[ConfigManager] WebGL 阶段1完成: {configDataMap.Count}/{totalConfigs} 个配置已加载到内存");
        // 阶段2: 从内存中分批解析初始化
        const int parseBatchSize = 10;
        int parsed = 0;
        foreach (var configType in configList)
        {
            if (configDataMap.TryGetValue(configType, out var texts))
            {
                InitConfigFromTexts(configType, texts);
            }
            parsed++;
            loadingProgress = 0.5f + 0.5f * parsed / totalConfigs;
            // 每 parseBatchSize 个让出主线程
            if (parsed % parseBatchSize == 0)
                await UniTask.Yield();
        }
#else
        List<UniTask> loadTasks = new List<UniTask>();
        // 逐个加载配置并更新进度
        foreach (var configType in configTypes)
        {
#if UNITY_EDITOR
            var sw = System.Diagnostics.Stopwatch.StartNew();
#endif
            UniTask uniTask = LoadConfigByTypeAsync(configType).ContinueWith(() =>
            {
            LoadConfigByType(configType);
            sw.Stop();
#if UNITY_EDITOR
                if (sw.ElapsedMilliseconds >= 100)
                {
                    Debug.LogWarning($"加载配置 {configType.Name} 耗时较长: {sw.ElapsedMilliseconds} ms");
                }
                else
                {
                    Debug.Log($"加载配置: {configType.Name} 用时: {sw.ElapsedMilliseconds} ms");
                }
                sw.Stop();
            if (sw.ElapsedMilliseconds >= 500)
            {
                Debug.LogError($"加载配置 {configType.Name} 耗时较长: {sw.ElapsedMilliseconds} ms");
            }
            else if (sw.ElapsedMilliseconds <= 5)
            {
                fastName.Add(configType.Name);
            }
            Debug.Log($"加载配置: {configType.Name} 用时: {sw.ElapsedMilliseconds} ms");
#endif
                loadingProgress = (float)(++iterator) / totalConfigs;
            });
            loadTasks.Add(uniTask);
            loadingProgress = (float)(iterator++ + 1) / totalConfigs;
        }
#if UNITY_EDITOR
        if (Launch.Instance.isOpenConfigTesting)
        {
            System.IO.File.WriteAllText(Application.dataPath + "/fastConfig.txt", string.Join("\n", fastName));
        await UniTask.WhenAll(loadTasks);
            //加载完后卸载
            foreach (var configType in configTypes)
            {
                var methodInfo = configType.GetMethod("ForceRelease", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.FlattenHierarchy);
                if (methodInfo != null)
                {
                    methodInfo.Invoke(null, null);
                }
            }
        }
#endif
        // 加载完成后设置isLoadFinished为true
@@ -272,64 +196,28 @@
        isLoadFinished = true;
    }
    // public void LoadConfigByType(Type configType)
    // {
    //     string configName = configType.Name;
    //     if (configName.EndsWith("Config"))
    //     {
    //         configName = configName.Substring(0, configName.Length - 6);
    //     }
    //     #pragma warning disable CS0618 // Obsolete — sync legacy fallback, use LoadConfigByTypeAsync
    //     string[] texts = ResManager.Instance.LoadConfig(configName);
    //     #pragma warning restore CS0618
    //     if (texts != null)
    //     {
    //         string[] lines = texts;
    //         var methodInfo = configType.GetMethod("Init", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.FlattenHierarchy);
    //         if (methodInfo != null)
    //         {
    //             methodInfo.Invoke(null, new object[] { lines });
    //             // 设置初始化标志
    //             var isInitField = configType.GetField("isInit", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
    //             if (isInitField != null)
    //             {
    //                 isInitField.SetValue(null, true);
    //             }
    //             Debug.Log($"加载配置: {configType.Name} 成功");
    //         }
    //         else
    //         {
    //             Debug.LogError($"配置类 {configType.Name} 没有静态Init方法");
    //         }
    //     }
    //     else
    //     {
    //         Debug.LogError($"找不到配置文件: {configName}");
    //     }
    // }
    /// <summary>
    /// US2: Async variant of LoadConfigByType. Uses UniTask-based config loading.
    /// </summary>
    public async UniTask LoadConfigByTypeAsync(Type configType)
    public void LoadConfigByType(Type configType)
    {
        string configName = configType.Name;
        if (configName.EndsWith("Config"))
        {
            configName = configName.Substring(0, configName.Length - 6);
        }
        string[] texts = await ResManager.Instance.LoadConfigAsync(configName);
        string[] texts = ResManager.Instance.LoadConfig(configName);
        if (texts != null)
        {
        var methodInfo = configType.GetMethod("Init", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.FlattenHierarchy);
            string[] lines = texts;
            var methodInfo = configType.GetMethod("Init", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.FlattenHierarchy);
            if (methodInfo != null)
            {
                methodInfo.Invoke(null, new object[] { texts });
                methodInfo.Invoke(null, new object[] { lines });
                // 设置初始化标志
                var isInitField = configType.GetField("isInit", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
                if (isInitField != null)
                {
                    isInitField.SetValue(null, true);
                }
                Debug.Log($"加载配置: {configType.Name} 成功");
            }
            else
            {
@@ -342,38 +230,36 @@
        }
    }
    // private async UniTask LoadConfig<T>() where T : class
    // {
    //     string configName = typeof(T).Name;
    private async UniTask LoadConfig<T>() where T : class
    {
        string configName = typeof(T).Name;
    //     #pragma warning disable CS0618
    //     string[] texts = ResManager.Instance.LoadConfig(configName);
    //     #pragma warning restore CS0618
    //     if (texts != null)
    //     {
    //         string[] lines = texts;
    //         var methodInfo = typeof(T).GetMethod("Init", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
    //         if (methodInfo != null)
    //         {
    //             methodInfo.Invoke(null, lines);
    //             // 设置初始化标志
    //             var isInitField = typeof(T).GetField("isInit", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
    //             if (isInitField != null)
    //             {
    //                 isInitField.SetValue(null, true);
    //             }
    //             Debug.Log($"加载配置: {typeof(T).Name} 成功");
    //         }
    //         else
    //         {
    //             Debug.LogError($"配置类 {typeof(T).Name} 没有静态Init方法");
    //         }
    //     }
    //     else
    //     {
    //         Debug.LogError($"找不到配置文件: {configName}");
    //     }
    // }
        string[] texts = ResManager.Instance.LoadConfig(configName);
        if (texts != null)
        {
            string[] lines = texts;
            var methodInfo = typeof(T).GetMethod("Init", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
            if (methodInfo != null)
            {
                methodInfo.Invoke(null, lines);
                // 设置初始化标志
                var isInitField = typeof(T).GetField("isInit", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
                if (isInitField != null)
                {
                    isInitField.SetValue(null, true);
                }
                Debug.Log($"加载配置: {typeof(T).Name} 成功");
            }
            else
            {
                Debug.LogError($"配置类 {typeof(T).Name} 没有静态Init方法");
            }
        }
        else
        {
            Debug.LogError($"找不到配置文件: {configName}");
        }
    }
    public float GetLoadingProgress()
    {
@@ -406,6 +292,14 @@
        ClearConfigDictionary<ActLunhuidianTypeConfig>();
        // 清空 ActSignAwardConfig 字典
        ClearConfigDictionary<ActSignAwardConfig>();
        // 清空 ActSignConfig 字典
        ClearConfigDictionary<ActSignConfig>();
        // 清空 ActSpecialSaleConfig 字典
        ClearConfigDictionary<ActSpecialSaleConfig>();
        // 清空 ActTaskConfig 字典
        ClearConfigDictionary<ActTaskConfig>();
        // 清空 ActTaskTempConfig 字典
        ClearConfigDictionary<ActTaskTempConfig>();
        // 清空 ActTotalRechargeConfig 字典
        ClearConfigDictionary<ActTotalRechargeConfig>();
        // 清空 ActTotalRechargeTempConfig 字典
@@ -530,6 +424,8 @@
        ClearConfigDictionary<PriorBundleConfig>();
        // 清空 RandomNameConfig 字典
        ClearConfigDictionary<RandomNameConfig>();
        // 清空 RobotConfig 字典
        ClearConfigDictionary<RobotConfig>();
        // 清空 SignInConfig 字典
        ClearConfigDictionary<SignInConfig>();
        // 清空 SkillSkinConfig 字典
@@ -566,22 +462,9 @@
        ClearConfigDictionary<ZhanlingConfig>();
    }
    /// <summary>
    /// 只加载配置文本,不做解析。用于 WebGL 批量预加载。
    /// </summary>
    private async UniTask<string[]> LoadConfigTextAsync(Type configType)
    {
        string configName = configType.Name;
        if (configName.EndsWith("Config"))
            configName = configName.Substring(0, configName.Length - 6);
        return await ResManager.Instance.LoadConfigAsync(configName);
    }
#if UNITY_EDITOR
    /// <summary>
    /// Editor 自检:反射加载所有配置类并记录耗时。
    /// </summary>
    public async void SelfCheckAllConfigs()
    [MenuItem("Tools/Config/自检")]
    public static void CheckAndGenerateFastConfig()
    {
        // 获取 Editor Assembly
        var editorAsm = System.AppDomain.CurrentDomain.GetAssemblies()
@@ -622,8 +505,8 @@
        foreach (var className in checkClasses)
        {
            // 这里也要用 Editor Assembly 获取类型
            var cfgType = editorAsm.GetType(className) ?? Type.GetType(className);
            if (cfgType == null)
            var configType = editorAsm.GetType(className) ?? Type.GetType(className);
            if (configType == null)
            {
                Debug.LogWarning($"[自检] 未找到类型: {className}");
                continue;
@@ -632,15 +515,15 @@
            var sw = System.Diagnostics.Stopwatch.StartNew();
            // 反射调用静态Init方法
            string configName = cfgType.Name;
            string configName = configType.Name;
            if (configName.EndsWith("Config"))
                configName = configName.Substring(0, configName.Length - 6);
            string[] texts = await ResManager.Instance.LoadConfigAsync(configName);
            string[] texts = ResManager.Instance.LoadConfig(configName);
            if (texts != null)
            {
                string[] lines = texts;
                var methodInfo = cfgType.GetMethod("Init", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.FlattenHierarchy);
                var methodInfo = configType.GetMethod("Init", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.FlattenHierarchy);
                if (methodInfo != null)
                {
                    methodInfo.Invoke(null, new object[] { lines });
@@ -651,21 +534,21 @@
            if (sw.ElapsedMilliseconds >= 500)
            {
                Debug.LogError($"[自检] 加载配置 {cfgType.Name} 耗时较长: {sw.ElapsedMilliseconds} ms");
                Debug.LogError($"[自检] 加载配置 {configType.Name} 耗时较长: {sw.ElapsedMilliseconds} ms");
            }
            else if (sw.ElapsedMilliseconds <= 5)
            {
                fastName.Add(cfgType.Name);
                fastName.Add(configType.Name);
            }
            Debug.Log($"[自检] 加载配置: {cfgType.Name} 用时: {sw.ElapsedMilliseconds} ms");
            Debug.Log($"[自检] 加载配置: {configType.Name} 用时: {sw.ElapsedMilliseconds} ms");
        }
        // 释放所有已加载的配置
        foreach (var className in checkClasses)
        {
            var cfgType = editorAsm.GetType(className) ?? Type.GetType(className);
            if (cfgType == null) continue;
            var methodInfo = cfgType.GetMethod("ForceRelease", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.FlattenHierarchy);
            var configType = editorAsm.GetType(className) ?? Type.GetType(className);
            if (configType == null) continue;
            var methodInfo = configType.GetMethod("ForceRelease", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.FlattenHierarchy);
            if (methodInfo != null)
            {
                methodInfo.Invoke(null, null);
@@ -676,26 +559,4 @@
        Debug.Log($"[自检] fastConfig.txt 生成完毕,快速表有:{string.Join(", ", fastName)}");
    }
#endif
    /// <summary>
    /// 从已加载的文本初始化配置(纯内存操作,无网络)。
    /// </summary>
    private void InitConfigFromTexts(Type configType, string[] texts)
    {
        var methodInfo = configType.GetMethod("Init",
            System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.FlattenHierarchy);
        if (methodInfo != null)
        {
            methodInfo.Invoke(null, new object[] { texts });
            var isInitField = configType.GetField("isInit",
                System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
            if (isInitField != null)
                isInitField.SetValue(null, true);
        }
        else
        {
            Debug.LogError($"配置类 {configType.Name} 没有静态Init方法");
        }
    }
}
Main/Config/Configs/ADAwardConfig.cs
@@ -1,6 +1,6 @@
//--------------------------------------------------------
//    [Author]:           YYL
//    [  Date ]:           2026年1月15日
//    [  Date ]:           Monday, April 27, 2026
//--------------------------------------------------------
using System.Collections.Generic;
@@ -24,6 +24,7 @@
    public int FuncID;
    public int RedpointID;
    public int ParentRedpointID;
    public string Name;
    public override int LoadKey(string _key)
    {
@@ -50,6 +51,8 @@
            int.TryParse(tables[6],out RedpointID); 
            int.TryParse(tables[7],out ParentRedpointID); 
            Name = tables[8];
        }
        catch (Exception exception)
        {
Main/Config/Configs/ActSignConfig.cs
New file
@@ -0,0 +1,41 @@
//--------------------------------------------------------
//    [Author]:           YYL
//    [  Date ]:           Tuesday, April 28, 2026
//--------------------------------------------------------
using System.Collections.Generic;
using System;
using UnityEngine;
using LitJson;
public partial class ActSignConfig : ConfigBase<int, ActSignConfig>
{
    static ActSignConfig()
    {
        // 访问过静态构造函数
        visit = true;
    }
    public int CfgID;
    public int SignTempID;
    public override int LoadKey(string _key)
    {
        int key = GetKey(_key);
        return key;
    }
    public override void LoadConfig(string input)
    {
        try {
        string[] tables = input.Split('\t');
        int.TryParse(tables[0],out CfgID);
            int.TryParse(tables[1],out SignTempID);
        }
        catch (Exception exception)
        {
            Debug.LogError(exception);
        }
    }
}
Main/Config/Configs/ActSignConfig.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 28335628185079b4cae244317f179653
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Config/Configs/ActSpecialSaleConfig.cs
New file
@@ -0,0 +1,62 @@
//--------------------------------------------------------
//    [Author]:           YYL
//    [  Date ]:           2026年4月29日
//--------------------------------------------------------
using System.Collections.Generic;
using System;
using UnityEngine;
using LitJson;
public partial class ActSpecialSaleConfig : ConfigBase<int, ActSpecialSaleConfig>
{
    static ActSpecialSaleConfig()
    {
        // 访问过静态构造函数
        visit = true;
    }
    public int CfgID;
    public int[] CTGIDList;
    public int ActShopType;
    public int ADID;
    public int[][] PopItems;
    public override int LoadKey(string _key)
    {
        int key = GetKey(_key);
        return key;
    }
    public override void LoadConfig(string input)
    {
        try {
        string[] tables = input.Split('\t');
        int.TryParse(tables[0],out CfgID);
            if (tables[1].Contains("["))
            {
                CTGIDList = JsonMapper.ToObject<int[]>(tables[1]);
            }
            else
            {
                string[] CTGIDListStringArray = tables[1].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                CTGIDList = new int[CTGIDListStringArray.Length];
                for (int i=0;i<CTGIDListStringArray.Length;i++)
                {
                     int.TryParse(CTGIDListStringArray[i],out CTGIDList[i]);
                }
            }
            int.TryParse(tables[2],out ActShopType);
            int.TryParse(tables[3],out ADID);
            PopItems = JsonMapper.ToObject<int[][]>(tables[4].Replace("(", "[").Replace(")", "]"));
        }
        catch (Exception exception)
        {
            Debug.LogError(exception);
        }
    }
}
Main/Config/Configs/ActSpecialSaleConfig.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fee90584a2c90bf429ad939a6a80973a
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Config/Configs/ActTaskConfig.cs
New file
@@ -0,0 +1,53 @@
//--------------------------------------------------------
//    [Author]:           YYL
//    [  Date ]:           Wednesday, April 29, 2026
//--------------------------------------------------------
using System.Collections.Generic;
using System;
using UnityEngine;
using LitJson;
public partial class ActTaskConfig : ConfigBase<int, ActTaskConfig>
{
    static ActTaskConfig()
    {
        // 访问过静态构造函数
        visit = true;
    }
    public int CfgID;
    public int IsDayReset;
    public int TemplateID;
    public int ActScoreItemID;
    public int ActShopTypeEx;
    public string ActScoreAwardInfo;
    public override int LoadKey(string _key)
    {
        int key = GetKey(_key);
        return key;
    }
    public override void LoadConfig(string input)
    {
        try {
        string[] tables = input.Split('\t');
        int.TryParse(tables[0],out CfgID);
            int.TryParse(tables[1],out IsDayReset);
            int.TryParse(tables[2],out TemplateID);
            int.TryParse(tables[3],out ActScoreItemID);
            int.TryParse(tables[4],out ActShopTypeEx);
            ActScoreAwardInfo = tables[5];
        }
        catch (Exception exception)
        {
            Debug.LogError(exception);
        }
    }
}
Main/Config/Configs/ActTaskConfig.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 18ccb33588d91924e929f132457591f2
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Config/Configs/ActTaskTempConfig.cs
New file
@@ -0,0 +1,56 @@
//--------------------------------------------------------
//    [Author]:           YYL
//    [  Date ]:           2026年4月28日
//--------------------------------------------------------
using System.Collections.Generic;
using System;
using UnityEngine;
using LitJson;
public partial class ActTaskTempConfig : ConfigBase<int, ActTaskTempConfig>
{
    static ActTaskTempConfig()
    {
        // 访问过静态构造函数
        visit = true;
    }
    public int ID;
    public int TemplateID;
    public int TasklD;
    public int TaskType;
    public int NeedValue;
    public int[][] AwardItemList;
    public int GuideID;
    public override int LoadKey(string _key)
    {
        int key = GetKey(_key);
        return key;
    }
    public override void LoadConfig(string input)
    {
        try {
        string[] tables = input.Split('\t');
        int.TryParse(tables[0],out ID);
            int.TryParse(tables[1],out TemplateID);
            int.TryParse(tables[2],out TasklD);
            int.TryParse(tables[3],out TaskType);
            int.TryParse(tables[4],out NeedValue);
            AwardItemList = JsonMapper.ToObject<int[][]>(tables[5].Replace("(", "[").Replace(")", "]"));
            int.TryParse(tables[6],out GuideID);
        }
        catch (Exception exception)
        {
            Debug.LogError(exception);
        }
    }
}
Main/Config/Configs/ActTaskTempConfig.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ec9a5f1c58db6994b8f558fc17c191d9
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Config/Configs/HorseSkinConfig.cs
@@ -1,6 +1,6 @@
//--------------------------------------------------------
//    [Author]:           YYL
//    [  Date ]:           Monday, April 13, 2026
//    [  Date ]:           Wednesday, April 29, 2026
//--------------------------------------------------------
using System.Collections.Generic;
@@ -34,6 +34,7 @@
    public string Icon;
    public int showType;
    public int sortOrder;
    public int pmaVertexColorsOpen;
    public override int LoadKey(string _key)
    {
@@ -128,6 +129,8 @@
            int.TryParse(tables[16],out showType); 
            int.TryParse(tables[17],out sortOrder); 
            int.TryParse(tables[18],out pmaVertexColorsOpen);
        }
        catch (Exception exception)
        {
Main/Config/Configs/RobotConfig.cs
New file
@@ -0,0 +1,38 @@
//--------------------------------------------------------
//    [Author]:           YYL
//    [  Date ]:           Thursday, May 7, 2026
//--------------------------------------------------------
using System.Collections.Generic;
using System;
using UnityEngine;
using LitJson;
public partial class RobotConfig : ConfigBase<int, RobotConfig>
{
    static RobotConfig()
    {
        // 访问过静态构造函数
        visit = true;
    }
    public int ID;
    public override int LoadKey(string _key)
    {
        int key = GetKey(_key);
        return key;
    }
    public override void LoadConfig(string input)
    {
        try {
        string[] tables = input.Split('\t');
        int.TryParse(tables[0],out ID);
        }
        catch (Exception exception)
        {
            Debug.LogError(exception);
        }
    }
}
Main/Config/Configs/RobotConfig.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fcdec0934a6834f498bdf03a22e215c5
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Config/PartialConfigs/ActTaskTempConfig.cs
New file
@@ -0,0 +1,63 @@
using System.Collections.Generic;
using UnityEngine;
public partial class ActTaskTempConfig : ConfigBase<int, ActTaskTempConfig>
{
    public static Dictionary<int, List<ActTaskTempConfig>> templateIDToConfigsDict = new Dictionary<int, List<ActTaskTempConfig>>();
    protected override void OnConfigParseCompleted()
    {
        if (!templateIDToConfigsDict.ContainsKey(TemplateID))
        {
            templateIDToConfigsDict[TemplateID] = new List<ActTaskTempConfig>();
        }
        templateIDToConfigsDict[TemplateID].Add(this);
    }
    public static List<ActTaskTempConfig> GetTemplateIDToConfigsDict(int templateID)
    {
        if (templateIDToConfigsDict.ContainsKey(templateID))
        {
            return templateIDToConfigsDict[templateID];
        }
        return null;
    }
    // 累计积分奖励配置
    public class TotalScoreAwardConfig
    {
        public int needScore;      // 所需积分
        public int recordIndex;    // 记录索引
        public int itemId;         // 奖励物品ID
        public int itemCount;      // 奖励物品数量
    }
    // 通过CfgID获取累计积分奖励列表
    public static List<TotalScoreAwardConfig> GetTotalScoreAwardListByCfgID(int cfgId)
    {
        var result = new List<TotalScoreAwardConfig>();
        var config = ActTaskConfig.Get(cfgId);
        if (config == null || string.IsNullOrEmpty(config.ActScoreAwardInfo) || config.ActScoreAwardInfo == "{}")
        {
            return result;
        }
        var dict = ConfigParse.ParseIntArrayDict(config.ActScoreAwardInfo);
        foreach (var kvp in dict)
        {
            var arr = kvp.Value;
            if (arr != null && arr.Length >= 3)
            {
                result.Add(new TotalScoreAwardConfig
                {
                    needScore = kvp.Key,
                    recordIndex = arr[0],
                    itemId = arr[1],
                    itemCount = arr[2]
                });
            }
        }
        return result;
    }
}
Main/Config/PartialConfigs/ActTaskTempConfig.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0f7b949b0b810ea4b83d18d7d1113caf
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA10_tagSCActSpecialSaleInfo.cs
New file
@@ -0,0 +1,14 @@
using UnityEngine;
using System.Collections;
// AA 10 特卖活动信息 #tagSCActSpecialSaleInfo
public class DTCAA10_tagSCActSpecialSaleInfo : DtcBasic
{
    public override void Done(GameNetPackBasic vNetPack)
    {
        base.Done(vNetPack);
        HAA10_tagSCActSpecialSaleInfo vNetData = vNetPack as HAA10_tagSCActSpecialSaleInfo;
        OperationTimeHepler.Instance.UpdateFlashSaleActivityInfo(vNetData);
    }
}
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA10_tagSCActSpecialSaleInfo.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 93050a26bbe6ce449a5021d8cdebc682
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA1A_tagSCActTotDayRechargePlayerInfo.cs
@@ -10,5 +10,6 @@
        base.Done(vNetPack);
        HAA1A_tagSCActTotDayRechargePlayerInfo vNetData = vNetPack as HAA1A_tagSCActTotDayRechargePlayerInfo;
        TotDayRechargeManager.Instance.UpdateTotDayRechargePlayerInfo(vNetData);
        FestivalActivityRechargeTotDayManager.Instance.UpdateTotDayRechargePlayerInfo(vNetData);
    }
}
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA1C_tagSCActTotalRechargePlayerInfo.cs
@@ -8,5 +8,6 @@
        base.Done(vNetPack);
        HAA1C_tagSCActTotalRechargePlayerInfo vNetData = vNetPack as HAA1C_tagSCActTotalRechargePlayerInfo;
        TotalRechargeManager.Instance.UpdateTotalRechargePlayerInfo(vNetData);
        FestivalActivityRechargeTotalManager.Instance.UpdateTotalRechargePlayerInfo(vNetData);
    }
}
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA23_tagSCActSignInfo.cs
New file
@@ -0,0 +1,14 @@
using UnityEngine;
using System.Collections;
// AA 23 签到活动信息 #tagSCActSignInfo
public class DTCAA23_tagSCActSignInfo : DtcBasic
{
    public override void Done(GameNetPackBasic vNetPack)
    {
        base.Done(vNetPack);
        HAA23_tagSCActSignInfo vNetData = vNetPack as HAA23_tagSCActSignInfo;
        OperationTimeHepler.Instance.UpdateCheckInActivityInfo(vNetData);
    }
}
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA23_tagSCActSignInfo.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7b92c42956c922f4689fb3d005ccd63c
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA71_tagSCActTaskInfo.cs
New file
@@ -0,0 +1,12 @@
using UnityEngine;
using System.Collections;
// AA 71 任务活动信息 #tagSCActTaskInfo
public class DTCAA71_tagSCActTaskInfo : DtcBasic {
    public override void Done(GameNetPackBasic vNetPack) {
        base.Done(vNetPack);
        HAA71_tagSCActTaskInfo vNetData = vNetPack as HAA71_tagSCActTaskInfo;
        OperationTimeHepler.Instance.UpdateMissionActivityInfo(vNetData);
    }
}
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA71_tagSCActTaskInfo.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e5bfd63d84d04a64295b1e67df4182ba
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA72_tagSCActTaskPlayerValueInfo.cs
New file
@@ -0,0 +1,12 @@
using UnityEngine;
using System.Collections;
// AA 72 任务活动玩家任务值 #tagSCActTaskPlayerValueInfo
public class DTCAA72_tagSCActTaskPlayerValueInfo : DtcBasic {
    public override void Done(GameNetPackBasic vNetPack) {
        base.Done(vNetPack);
        HAA72_tagSCActTaskPlayerValueInfo vNetData = vNetPack as HAA72_tagSCActTaskPlayerValueInfo;
        FestivalActivityMissionManager.Instance.UpdatePlayerValueInfo(vNetData);
    }
}
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA72_tagSCActTaskPlayerValueInfo.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ff88da8b58bd357419087982180462a2
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA73_tagSCActTaskPlayerInfo.cs
New file
@@ -0,0 +1,12 @@
using UnityEngine;
using System.Collections;
// AA 73 任务活动玩家信息 #tagSCActTaskPlayerInfo
public class DTCAA73_tagSCActTaskPlayerInfo : DtcBasic {
    public override void Done(GameNetPackBasic vNetPack) {
        base.Done(vNetPack);
        HAA73_tagSCActTaskPlayerInfo vNetData = vNetPack as HAA73_tagSCActTaskPlayerInfo;
        FestivalActivityMissionManager.Instance.UpdatePlayerInfo(vNetData);
    }
}
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA73_tagSCActTaskPlayerInfo.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2622ac73ea207bc41b42b0bea6da8886
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Core/NetworkPackage/DataToCtl/PackageRegedit.cs
@@ -167,6 +167,11 @@
        Register(typeof(HAA1B_tagSCActTotDayRechargeInfo), typeof(DTCAA1B_tagSCActTotDayRechargeInfo));
        Register(typeof(HAA1C_tagSCActTotalRechargePlayerInfo), typeof(DTCAA1C_tagSCActTotalRechargePlayerInfo));
        Register(typeof(HAA1D_tagSCActTotalRechargeInfo), typeof(DTCAA1D_tagSCActTotalRechargeInfo));
        Register(typeof(HAA10_tagSCActSpecialSaleInfo), typeof(DTCAA10_tagSCActSpecialSaleInfo));
        Register(typeof(HAA23_tagSCActSignInfo), typeof(DTCAA23_tagSCActSignInfo));
        Register(typeof(HAA71_tagSCActTaskInfo), typeof(DTCAA71_tagSCActTaskInfo));
        Register(typeof(HAA72_tagSCActTaskPlayerValueInfo), typeof(DTCAA72_tagSCActTaskPlayerValueInfo));
        Register(typeof(HAA73_tagSCActTaskPlayerInfo), typeof(DTCAA73_tagSCActTaskPlayerInfo));
    }
    //主工程注册封包
Main/Core/NetworkPackage/ServerPack/HA9_Function/HA922_tagSCArenaMatchList.cs
@@ -25,6 +25,7 @@
            TransBytes (out MatchList[i].Face, vBytes, NetDataType.DWORD);
            TransBytes (out MatchList[i].FacePic, vBytes, NetDataType.DWORD);
            TransBytes (out MatchList[i].TitleID, vBytes, NetDataType.DWORD);
            TransBytes (out MatchList[i].ServerID, vBytes, NetDataType.DWORD);
        }
    }
@@ -38,6 +39,7 @@
        public uint Face;        //基本脸型
        public uint FacePic;        //头像框
        public uint TitleID;        //称号
        public uint ServerID;
    }
}
Main/Core/NetworkPackage/ServerPack/HAA_SaleActivity/HAA10_tagSCActSpecialSaleInfo.cs
New file
@@ -0,0 +1,23 @@
using UnityEngine;
using System.Collections;
// AA 10 特卖活动信息 #tagSCActSpecialSaleInfo
public class HAA10_tagSCActSpecialSaleInfo : GameNetPackBasic {
    public byte ActNum;    // 活动编号
    public string StartDate;    // 开始日期 y-m-d
    public string EndtDate;    // 结束日期 y-m-d
    public ushort CfgID;    // 活动时间表配置ID
    public HAA10_tagSCActSpecialSaleInfo () {
        _cmd = (ushort)0xAA10;
    }
    public override void ReadFromBytes (byte[] vBytes) {
        TransBytes (out ActNum, vBytes, NetDataType.BYTE);
        TransBytes (out StartDate, vBytes, NetDataType.Chars, 10);
        TransBytes (out EndtDate, vBytes, NetDataType.Chars, 10);
        TransBytes (out CfgID, vBytes, NetDataType.WORD);
    }
}
Main/Core/NetworkPackage/ServerPack/HAA_SaleActivity/HAA10_tagSCActSpecialSaleInfo.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0cedf55511caa534a998927e86ba2ac5
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Core/NetworkPackage/ServerPack/HAA_SaleActivity/HAA23_tagSCActSignInfo.cs
New file
@@ -0,0 +1,23 @@
using UnityEngine;
using System.Collections;
// AA 23 签到活动信息 #tagSCActSignInfo
public class HAA23_tagSCActSignInfo : GameNetPackBasic {
    public byte ActNum;    // 活动编号
    public string StartDate;    // 开始日期 y-m-d
    public string EndtDate;    // 结束日期 y-m-d
    public ushort CfgID;    // 活动时间表配置ID
    public HAA23_tagSCActSignInfo () {
        _cmd = (ushort)0xAA23;
    }
    public override void ReadFromBytes (byte[] vBytes) {
        TransBytes (out ActNum, vBytes, NetDataType.BYTE);
        TransBytes (out StartDate, vBytes, NetDataType.Chars, 10);
        TransBytes (out EndtDate, vBytes, NetDataType.Chars, 10);
        TransBytes (out CfgID, vBytes, NetDataType.WORD);
    }
}
Main/Core/NetworkPackage/ServerPack/HAA_SaleActivity/HAA23_tagSCActSignInfo.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e62482e93459c95489f5f137a1367382
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Core/NetworkPackage/ServerPack/HAA_SaleActivity/HAA71_tagSCActTaskInfo.cs
New file
@@ -0,0 +1,23 @@
using UnityEngine;
using System.Collections;
// AA 71 任务活动信息 #tagSCActTaskInfo
public class HAA71_tagSCActTaskInfo : GameNetPackBasic {
    public byte ActNum;    // 活动编号
    public string StartDate;    // 开始日期 y-m-d
    public string EndtDate;    // 结束日期 y-m-d
    public ushort CfgID;    // 活动时间表配置ID
    public HAA71_tagSCActTaskInfo () {
        _cmd = (ushort)0xAA71;
    }
    public override void ReadFromBytes (byte[] vBytes) {
        TransBytes (out ActNum, vBytes, NetDataType.BYTE);
        TransBytes (out StartDate, vBytes, NetDataType.Chars, 10);
        TransBytes (out EndtDate, vBytes, NetDataType.Chars, 10);
        TransBytes (out CfgID, vBytes, NetDataType.WORD);
    }
}
Main/Core/NetworkPackage/ServerPack/HAA_SaleActivity/HAA71_tagSCActTaskInfo.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 43a1369401f48644886a0ed6ead11c9a
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Core/NetworkPackage/ServerPack/HAA_SaleActivity/HAA72_tagSCActTaskPlayerValueInfo.cs
New file
@@ -0,0 +1,31 @@
using UnityEngine;
using System.Collections;
// AA 72 任务活动玩家任务值 #tagSCActTaskPlayerValueInfo
public class HAA72_tagSCActTaskPlayerValueInfo : GameNetPackBasic {
    public byte ActNum;    // 活动编号
    public byte TaskCount;
    public  tagSCActTaskPlayerValue[] TaskValueList;    // 有同步的任务类型直接覆盖即可
    public HAA72_tagSCActTaskPlayerValueInfo () {
        _cmd = (ushort)0xAA72;
    }
    public override void ReadFromBytes (byte[] vBytes) {
        TransBytes (out ActNum, vBytes, NetDataType.BYTE);
        TransBytes (out TaskCount, vBytes, NetDataType.BYTE);
        TaskValueList = new tagSCActTaskPlayerValue[TaskCount];
        for (int i = 0; i < TaskCount; i ++) {
            TaskValueList[i] = new tagSCActTaskPlayerValue();
            TransBytes (out TaskValueList[i].TaskType, vBytes, NetDataType.BYTE);
            TransBytes (out TaskValueList[i].TaskValue, vBytes, NetDataType.DWORD);
        }
    }
    public class tagSCActTaskPlayerValue {
        public byte TaskType;        // 任务类型
        public uint TaskValue;        // 当前任务值,所有相同任务类型共享该进度值
    }
}
Main/Core/NetworkPackage/ServerPack/HAA_SaleActivity/HAA72_tagSCActTaskPlayerValueInfo.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e3ae0803689cf9c41a5e5fdf2674875a
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Core/NetworkPackage/ServerPack/HAA_SaleActivity/HAA73_tagSCActTaskPlayerInfo.cs
New file
@@ -0,0 +1,25 @@
using UnityEngine;
using System.Collections;
// AA 73 任务活动玩家信息 #tagSCActTaskPlayerInfo
public class HAA73_tagSCActTaskPlayerInfo : GameNetPackBasic {
    public byte ActNum;    // 活动编号
    public uint ActScoreTotal;    // 累计活动积分,用于验证领取累计积分奖励用,商店兑换直接用物品兑换物品
    public uint ActScoreAward;    // 累计活动积分领奖记录,按奖励索引位运算判断是否已领取
    public byte AwardCount;
    public  uint[] AwardRecordList;    // 任务ID领奖记录值列表,根据任务ID位判断是否已领取,一个记录值存31位 [记录值0, 记录值1, ...]
    public HAA73_tagSCActTaskPlayerInfo () {
        _cmd = (ushort)0xAA73;
    }
    public override void ReadFromBytes (byte[] vBytes) {
        TransBytes (out ActNum, vBytes, NetDataType.BYTE);
        TransBytes (out ActScoreTotal, vBytes, NetDataType.DWORD);
        TransBytes (out ActScoreAward, vBytes, NetDataType.DWORD);
        TransBytes (out AwardCount, vBytes, NetDataType.BYTE);
        TransBytes (out AwardRecordList, vBytes, NetDataType.DWORD, AwardCount);
    }
}
Main/Core/NetworkPackage/ServerPack/HAA_SaleActivity/HAA73_tagSCActTaskPlayerInfo.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 822917aa36513164eaa88bab3498a208
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Main.cs
@@ -143,7 +143,11 @@
        managers.Add(CrossServerBaseManager.Instance);
        managers.Add(TotalRechargeManager.Instance);
        managers.Add(TotDayRechargeManager.Instance);
        managers.Add(FestivalActivityManager.Instance);
        managers.Add(FestivalActivityRechargeTotalManager.Instance);
        managers.Add(FestivalActivityRechargeTotDayManager.Instance);
        managers.Add(FestivalActivityCheckInManager.Instance);
        managers.Add(FestivalActivityMissionManager.Instance);
        foreach (var manager in managers)
        {
Main/System/Arena/ArenaBattleFailWin.cs
@@ -69,17 +69,13 @@
        myAvatarCell.InitUI(AvatarHelper.GetAvatarModel((int)PlayerDatas.Instance.baseData.PlayerID,
                                                PlayerDatas.Instance.baseData.face,
                                                PlayerDatas.Instance.baseData.facePic)).Forget();
        enemyAvatarCell.InitUI(AvatarHelper.GetAvatarModel((int)tagPlayerID, (int)enemyFace, (int)enemyFacePic)).Forget();
        enemyAvatarCell.SetOnLoaded(() =>
                                                PlayerDatas.Instance.baseData.facePic));
        enemyAvatarCell.InitUI(AvatarHelper.GetAvatarModel((int)tagPlayerID, (int)enemyFace, (int)enemyFacePic));
        enemyAvatarCell.SetListener(() =>
        {
            if (this == null) return;
            enemyAvatarCell.SetListener(() =>
            {
                AvatarHelper.TryViewOtherPlayerInfo((int)tagPlayerID, viewPlayerLineupType: (int)BattlePreSetType.Arena);
            });
            int serverID = (ArenaManager.Instance.IsOpenCrossServer() && tagPlayerID != PlayerDatas.Instance.baseData.PlayerID) ? (int)info.ServerID : 0;
            AvatarHelper.TryViewOtherPlayerInfo((int)tagPlayerID, serverID, viewPlayerLineupType: (int)BattlePreSetType.Arena);
        });
        txtMyName.text = PlayerDatas.Instance.baseData.PlayerName;
        txtEnemyName.text = UIHelper.ServerStringTrim(info.PlayerName);
Main/System/Arena/ArenaBattleVictoryWin.cs
@@ -63,15 +63,12 @@
        myAvatarCell.InitUI(AvatarHelper.GetAvatarModel((int)PlayerDatas.Instance.baseData.PlayerID,
                                                PlayerDatas.Instance.baseData.face,
                                                PlayerDatas.Instance.baseData.facePic)).Forget();
        enemyAvatarCell.InitUI(AvatarHelper.GetAvatarModel((int)tagPlayerID, (int)enemyFace, (int)enemyFacePic)).Forget();
        enemyAvatarCell.SetOnLoaded(() =>
                                                PlayerDatas.Instance.baseData.facePic));
        enemyAvatarCell.InitUI(AvatarHelper.GetAvatarModel((int)tagPlayerID, (int)enemyFace, (int)enemyFacePic));
        enemyAvatarCell.SetListener(() =>
        {
            if (this == null) return;
            enemyAvatarCell.SetListener(() =>
            {
                AvatarHelper.TryViewOtherPlayerInfo((int)tagPlayerID, viewPlayerLineupType: (int)BattlePreSetType.Arena);
            });
            int serverID = (ArenaManager.Instance.IsOpenCrossServer() && tagPlayerID != PlayerDatas.Instance.baseData.PlayerID) ? (int)info.ServerID : 0;
            AvatarHelper.TryViewOtherPlayerInfo((int)tagPlayerID, serverID, viewPlayerLineupType: (int)BattlePreSetType.Arena);
        });
        txtMyName.text = PlayerDatas.Instance.baseData.PlayerName;
Main/System/Arena/ArenaChallengeCell.cs
@@ -1,5 +1,4 @@
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using System.Collections.Generic;
using UnityEngine;
public class ArenaChallengeCell : MonoBehaviour
@@ -7,6 +6,8 @@
    [SerializeField] AvatarCell avatarCell;
    [SerializeField] TextEx txtName;
    [SerializeField] TextEx txtAddScore;
    [SerializeField] TextEx txtServerName;
    [SerializeField] TextEx txtAddCrossScore;
    [SerializeField] TextEx txtFightPoint;
    [SerializeField] OfficialTitleCell officialTitleCell;
    [SerializeField] List<ItemCell> itemCells;
@@ -33,20 +34,37 @@
            return;
        arenaMatchInfo = list[index];
        avatarCell.InitUI(AvatarHelper.GetAvatarModel((int)arenaMatchInfo.PlayerID, (int)arenaMatchInfo.Face, (int)arenaMatchInfo.FacePic)).Forget();
        avatarCell.SetOnLoaded(() =>
        avatarCell.InitUI(AvatarHelper.GetAvatarModel((int)arenaMatchInfo.PlayerID, (int)arenaMatchInfo.Face, (int)arenaMatchInfo.FacePic));
        avatarCell.SetListener(() =>
        {
            avatarCell.SetListener(() =>
            {
                AvatarHelper.TryViewOtherPlayerInfo((int)arenaMatchInfo.PlayerID, viewPlayerLineupType: (int)BattlePreSetType.Arena);
            });
            int serverID = (ArenaManager.Instance.IsOpenCrossServer() && arenaMatchInfo.PlayerID != PlayerDatas.Instance.baseData.PlayerID) ? (int)arenaMatchInfo.ServerID : 0;
            AvatarHelper.TryViewOtherPlayerInfo((int)arenaMatchInfo.PlayerID, serverID, viewPlayerLineupType: (int)BattlePreSetType.Arena);
        });
        txtName.text = UIHelper.ServerStringTrim(arenaMatchInfo.PlayerName);
        txtFightPoint.text = UIHelper.ReplaceLargeArtNum(arenaMatchInfo.FightPower);
        txtAddScore.text = Language.Get("Arena16", ArenaManager.Instance.GetChallengePoints(index));
        officialTitleCell.InitUI(arenaMatchInfo.RealmLV, (int)arenaMatchInfo.TitleID, 0.55f).Forget();
        bool isCrossServer = ArenaManager.Instance.IsOpenCrossServer();
        if (isCrossServer)
        {
            txtAddScore.SetActive(false);
            txtServerName.SetActive(true);
            if (ArenaManager.Instance.IsRobot((int)arenaMatchInfo.PlayerID))
                txtServerName.text = ServerListCenter.Instance.GetServerName(UIHelper.GetServerIDByAccount(PlayerDatas.Instance.baseData.AccID));
            else
                txtServerName.text = ServerListCenter.Instance.GetServerName((int)arenaMatchInfo.ServerID);
            txtAddCrossScore.SetActive(true);
            txtAddCrossScore.text = Language.Get("Arena16", ArenaManager.Instance.GetChallengePoints(index));
        }
        else
        {
            txtAddScore.SetActive(true);
            txtAddScore.text = Language.Get("Arena16", ArenaManager.Instance.GetChallengePoints(index));
            txtServerName.SetActive(false);
            txtAddCrossScore.SetActive(false);
        }
        officialTitleCell.InitUI(arenaMatchInfo.RealmLV, (int)arenaMatchInfo.TitleID, 0.55f);
        int[][] rewards = ArenaManager.Instance.fixedChallengeRewards;
        for (int i = 0; i < itemCells.Count; i++)
@@ -57,7 +75,7 @@
                int itemCellIndex = i;
                itemCell.SetActive(true);
                itemCell.Init(new ItemCellModel(rewards[i][0], true, rewards[i][1]));
                itemCell.SetClickListener(() => ItemTipUtility.Show(rewards[itemCellIndex][0]));
                itemCell.button.SetListener(() => ItemTipUtility.Show(rewards[itemCellIndex][0]));
            }
            else
            {
@@ -65,4 +83,4 @@
            }
        }
    }
}
}
Main/System/Arena/ArenaCrossAwardCell.cs
New file
@@ -0,0 +1,69 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
/// <summary>
/// 竞技场奖励单元格
/// </summary>
public class ArenaCrossAwardCell : CellView
{
    [SerializeField] ImageEx imgRank;
    [SerializeField] TextEx txtRank;
    [SerializeField] ItemCell[] itemCells;
    public void Display(int index, CellView cellView)
    {
        int functionOrder = cellView.info.Value.infoInt1;
        var rewardDict = ArenaManager.Instance.GetCrossArenaAwardDict(functionOrder);
        if (rewardDict.IsNullOrEmpty()) return;
        var sortedKeys = rewardDict.Keys.ToList();
        sortedKeys.Sort();
        DisplayRank(sortedKeys, index);
        DisplayItems(sortedKeys, index, rewardDict);
    }
    private void DisplayRank(List<int> sortedKeys, int index)
    {
        int rank = sortedKeys[index];
        if (rank <= 3)
        {
            imgRank.SetActive(true);
            txtRank.SetActive(false);
            imgRank.SetSprite($"Rank{rank}");
        }
        else
        {
            imgRank.SetActive(false);
            txtRank.SetActive(true);
            int lastIndex = index - 1;
            txtRank.text = lastIndex > 0 && lastIndex < sortedKeys.Count
                ? Language.Get("Arena15", sortedKeys[lastIndex] + 1, rank)
                : string.Empty;
        }
    }
    private void DisplayItems(List<int> sortedKeys, int index, Dictionary<int, int[][]> rewardDict)
    {
        int[][] rewardArr = rewardDict[sortedKeys[index]];
        if (rewardArr.IsNullOrEmpty())
        {
            for (int i = 0; i < itemCells.Length; i++)
                itemCells[i].SetActive(false);
            return;
        }
        for (int i = 0; i < itemCells.Length; i++)
        {
            bool hasReward = i < rewardArr.Length;
            itemCells[i].SetActive(hasReward);
            if (hasReward)
            {
                int itemId = rewardArr[i][0];
                itemCells[i].Init(new ItemCellModel(itemId, true, rewardArr[i][1]));
                itemCells[i].button.SetListener(() => ItemTipUtility.Show(itemId));
            }
        }
    }
}
Main/System/Arena/ArenaCrossAwardCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: db50e766c48693241827170a23113478
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/Arena/ArenaCrossAwardWin.cs
New file
@@ -0,0 +1,192 @@
using System;
using System.Linq;
using UnityEngine;
/// <summary>
/// 竞技场奖励窗口:functionOrder=0/1/2 → 本服日/本服周/跨服周奖励
/// </summary>
public class ArenaCrossAwardWin : FunctionsBaseWin
{
    [HideInInspector] public string valueFormat = "{0}";
    [SerializeField] ArenaPlayerRankCell myRankCell;
    [SerializeField] ButtonEx btnClose;
    [SerializeField] TextEx txtCountdown;
    [SerializeField] Transform localDayRect;
    [SerializeField] ScrollerController scrLocalDayAward;
    [SerializeField] Transform localWeekRect;
    [SerializeField] ScrollerController scrLocalWeekAward;
    [SerializeField] Transform crossWeekRect;
    [SerializeField] ScrollerController scrCrossWeekAward;
    protected override void InitComponent()
    {
        base.InitComponent();
        btnClose.SetListener(CloseWindow);
    }
    protected override void OnPreOpen()
    {
        base.OnPreOpen();
        ArenaManager.Instance.OnArenaMatchListEvent += OnArenaMatchListEvent;
        ArenaManager.Instance.OnUpdateArenaPlayerInfo += OnUpdateArenaPlayerInfo;
        ArenaManager.Instance.OnUpdateGameRecInfo += OnUpdateGameRecInfo;
        RankModel.Instance.onRankRefresh += OnRankRefresh;
        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
        scrLocalDayAward.OnRefreshCell += OnRefreshLocalDayCell;
        scrLocalWeekAward.OnRefreshCell += OnRefreshLocalWeekCell;
        scrCrossWeekAward.OnRefreshCell += OnRefreshCrossWeekCell;
        Display();
    }
    protected override void OnPreClose()
    {
        base.OnPreClose();
        ArenaManager.Instance.OnArenaMatchListEvent -= OnArenaMatchListEvent;
        ArenaManager.Instance.OnUpdateArenaPlayerInfo -= OnUpdateArenaPlayerInfo;
        ArenaManager.Instance.OnUpdateGameRecInfo -= OnUpdateGameRecInfo;
        RankModel.Instance.onRankRefresh -= OnRankRefresh;
        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
        scrLocalDayAward.OnRefreshCell -= OnRefreshLocalDayCell;
        scrLocalWeekAward.OnRefreshCell -= OnRefreshLocalWeekCell;
        scrCrossWeekAward.OnRefreshCell -= OnRefreshCrossWeekCell;
    }
    private void OnSecondEvent()
    {
        TimeSpan remainingTime;
        if (functionOrder == 0)
        {
            // 本服日奖励:使用到明天0点的时间
            remainingTime = TimeUtility.ServerNow.AddDays(1).Date - TimeUtility.ServerNow;
        }
        else if (functionOrder == 1)
        {
            // 本服周奖励:使用本服赛季结束时间
            ArenaManager.Instance.GetCurrentSeasonDates(out _, out DateTime seasonEndDate);
            remainingTime = seasonEndDate - TimeUtility.ServerNow;
        }
        else
        {
            // 跨服周奖励:使用跨服赛季结束时间
            var crossZoneInfo = CrossServerBaseManager.Instance.GetCrossZoneInfo(ArenaManager.Instance.DataMapID);
            int zoneID = crossZoneInfo != null ? (int)crossZoneInfo.ZoneID : 0;
            ArenaManager.Instance.GetCrossCurrentSeasonDates(zoneID, out _, out DateTime crossSeasonEndDate);
            remainingTime = crossSeasonEndDate - TimeUtility.ServerNow;
        }
        int remainingSeconds = (int)remainingTime.TotalSeconds;
        bool hasTime = remainingSeconds > 0;
        txtCountdown.SetActive(hasTime);
        if (hasTime)
            txtCountdown.text = Language.Get("Arena14", TimeUtility.SecondsToDHMSCHS(remainingSeconds));
    }
    protected override void OpenSubUIByTabIndex()
    {
        Display();
    }
    private void OnRefreshLocalDayCell(ScrollerDataType type, CellView cell)
    {
        cell.GetComponent<ArenaCrossAwardCell>()?.Display(cell.index, cell);
    }
    private void OnRefreshLocalWeekCell(ScrollerDataType type, CellView cell)
    {
        cell.GetComponent<ArenaCrossAwardCell>()?.Display(cell.index, cell);
    }
    private void OnRefreshCrossWeekCell(ScrollerDataType type, CellView cell)
    {
        cell.GetComponent<ArenaCrossAwardCell>()?.Display(cell.index, cell);
    }
    private void OnArenaMatchListEvent() => Display();
    private void OnUpdateArenaPlayerInfo() => Display();
    private void OnUpdateGameRecInfo() => Display();
    private void OnRankRefresh(int _) => DisplayMyRank();
    private void Display()
    {
        localDayRect.SetActive(functionOrder == 0);
        localWeekRect.SetActive(functionOrder == 1);
        crossWeekRect.SetActive(functionOrder == 2);
        CreateScroller();
        DisplayMyRank();
        OnSecondEvent();
    }
    private void CreateScroller()
    {
        switch (functionOrder)
        {
            case 0:
                CreateLocalDayScroller();
                break;
            case 1:
                CreateLocalWeekScroller();
                break;
            case 2:
                CreateCrossWeekScroller();
                break;
        }
        DisplayMyRank();
        OnSecondEvent();
    }
    private void CreateLocalDayScroller()
    {
        scrLocalDayAward.Refresh();
        var rewardDict = ArenaManager.Instance.GetCrossArenaAwardDict(0);
        if (rewardDict.IsNullOrEmpty()) return;
        var sortedKeys = rewardDict.Keys.ToList();
        sortedKeys.Sort();
        CellInfo cellInfo = new CellInfo { infoInt1 = 0 };
        for (int i = 0; i < sortedKeys.Count; i++)
            scrLocalDayAward.AddCell(ScrollerDataType.Header, i, cellInfo);
        scrLocalDayAward.Restart();
    }
    private void CreateLocalWeekScroller()
    {
        scrLocalWeekAward.Refresh();
        var rewardDict = ArenaManager.Instance.GetCrossArenaAwardDict(1);
        if (rewardDict.IsNullOrEmpty()) return;
        var sortedKeys = rewardDict.Keys.ToList();
        sortedKeys.Sort();
        CellInfo cellInfo = new CellInfo { infoInt1 = 1 };
        for (int i = 0; i < sortedKeys.Count; i++)
            scrLocalWeekAward.AddCell(ScrollerDataType.Header, i, cellInfo);
        scrLocalWeekAward.Restart();
    }
    private void CreateCrossWeekScroller()
    {
        scrCrossWeekAward.Refresh();
        var rewardDict = ArenaManager.Instance.GetCrossArenaAwardDict(2);
        if (rewardDict.IsNullOrEmpty()) return;
        var sortedKeys = rewardDict.Keys.ToList();
        sortedKeys.Sort();
        CellInfo cellInfo = new CellInfo { infoInt1 = 2 };
        for (int i = 0; i < sortedKeys.Count; i++)
            scrCrossWeekAward.AddCell(ScrollerDataType.Header, i, cellInfo);
        scrCrossWeekAward.Restart();
    }
    private void DisplayMyRank()
    {
        myRankCell.Display(ArenaManager.Instance.rankType, 0, valueFormat);
    }
}
Main/System/Arena/ArenaCrossAwardWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f638d0723d6fc9347ac43f23a5a2f944
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/Arena/ArenaManager.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using LitJson;
using System;
@@ -6,6 +7,7 @@
public class ArenaManager : GameSystemManager<ArenaManager>
{
    public readonly int rankType = 1;    // 榜单类型
    public readonly int corssRankType = 151;    // 榜单类型
    public readonly int funcId = 27;    // 功能Id
    public readonly int DeployTroopsFuncId = 31;    // 布阵功能ID
    public readonly int BattleChangeTabFuncId = 32; // 战斗能切换页签功能ID
@@ -26,6 +28,8 @@
    public Dictionary<int, int[][]> dailyRankRewards; // 每日排行奖励 {"名次":[[物品ID, 个数,是否拍品], ...], ...} 配置的名次key,自动按小于等于对应名次给奖励
    public Dictionary<int, int[][]> seasonRankRewards;  // 赛季排行奖励 {"名次":[[物品ID, 个数,是否拍品], ...], ...}
    public Dictionary<int, int> crossRewardTemps;//数值2:跨服赛季排行奖励模版 {"互通服务器数";对应活动排行奖励表模版编号, ...}  按小于等于判断,大于最大配置的服务器数时默认取配置中最大服务器数对应奖励
    public Dictionary<int, int[][]> crossWeekRewards;
    public uint score;    // 当前积分
    public int totalWinCnt;  //累计胜利次数
@@ -40,18 +44,97 @@
    public event Action OnArenaMatchListEvent;
    public event Action OnUpdateArenaPlayerInfo;
    public event Action OnUpdateGameRecInfo;
    private int lastLocalWeekday;        // 上次本服weekday (1-7, 周一=1, 周日=7)
    private int lastCrossWeekday;        // 上次跨服weekday
    public override void Init()
    {
        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEventOnRelogin += BeforePlayerDataInitializeEventOnRelogin;
        PlayerDatas.Instance.playerDataRefreshEvent += PlayerDataRefresh;
        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
        CrossServerBaseManager.Instance.OnCrossZoneInfoUpdateEvent += OnCrossZoneInfoUpdate;
        InitTable();
        InitRedpoint();
        InitCrossServerState();
    }
    public override void Release()
    {
        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEventOnRelogin -= BeforePlayerDataInitializeEventOnRelogin;
        PlayerDatas.Instance.playerDataRefreshEvent -= PlayerDataRefresh;
        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
        CrossServerBaseManager.Instance.OnCrossZoneInfoUpdateEvent -= OnCrossZoneInfoUpdate;
    }
    void InitCrossServerState()
    {
        lastLocalWeekday = TimeUtility.GetCommonWeekday(); // zoneID=0本服
        int crossZoneID = GetCrossZoneID();
        lastCrossWeekday = crossZoneID > 0 ? TimeUtility.GetCommonWeekday(crossZoneID) : lastLocalWeekday;
    }
    void OnSecondEvent()
    {
        CheckCrossWeekChange();
    }
    // 跨服状态更新事件处理
    void OnCrossZoneInfoUpdate(int mapID)
    {
        if (mapID != DataMapID)
            return;
        bool currentIsOpenCrossServer = IsOpenCrossServer();
        // 只会从未跨服变为跨服,变为跨服时关闭ArenaWin
        if (currentIsOpenCrossServer)
        {
            CloseArenaWinAndClearData();
        }
        int crossZoneID = GetCrossZoneID();
        lastCrossWeekday = crossZoneID > 0 ? TimeUtility.GetCommonWeekday(crossZoneID) : TimeUtility.GetCommonWeekday();
    }
    int GetCrossZoneID()
    {
        var crossZoneInfo = CrossServerBaseManager.Instance.GetCrossZoneInfo(DataMapID);
        return crossZoneInfo != null ? (int)crossZoneInfo.ZoneID : 0;
    }
    void CheckCrossWeekChange()
    {
        int currentLocalWeekday = TimeUtility.GetCommonWeekday(); // zoneID=0本服
        int crossZoneID = GetCrossZoneID();
        int currentCrossWeekday = crossZoneID > 0 ? TimeUtility.GetCommonWeekday(crossZoneID) : currentLocalWeekday;
        // 条件1: 本服时间过周 (weekday从7变为1, 周日->周一)
        if (lastLocalWeekday == 7 && currentLocalWeekday == 1)
        {
            CloseArenaWinAndClearData();
        }
        lastLocalWeekday = currentLocalWeekday;
        bool currentIsOpenCrossServer = IsOpenCrossServer();
        if (!currentIsOpenCrossServer)
            return;
        // 条件2: 跨服时间过周 (weekday从7变为1, 周日->周一)
        if (crossZoneID > 0 && lastCrossWeekday == 7 && currentCrossWeekday == 1)
        {
            CloseArenaWinAndClearData();
        }
        lastCrossWeekday = currentCrossWeekday;
    }
    void CloseArenaWinAndClearData()
    {
        if (UIManager.Instance.IsOpened<ArenaWin>())
        {
            UIManager.Instance.CloseWindow<ArenaWin>();
        }
        matchInfoList.Clear();
        gameRecDict.Clear();
    }
    public void BeforePlayerDataInitializeEventOnRelogin()
@@ -86,6 +169,9 @@
        config = FuncConfigConfig.Get("ArenaBillboradAward");
        dailyRankRewards = ConfigParse.ParseIntArray2Dict(config.Numerical1);
        seasonRankRewards = ConfigParse.ParseIntArray2Dict(config.Numerical2);
        config = FuncConfigConfig.Get("ArenaCross");
        crossRewardTemps = ConfigParse.ParseIntDict(config.Numerical2);
    }
    public void UpdateRedPonit()
    {
@@ -141,7 +227,9 @@
                RealmLV = item.RealmLV,
                FightPower = (ulong)item.FightPowerEx * 100000000 + (ulong)item.FightPower,
                Face = item.Face,
                FacePic = item.FacePic
                FacePic = item.FacePic,
                TitleID = item.TitleID,
                ServerID = item.ServerID,
            };
            matchInfoList.Add(matchInfo);
            allFaceInfoDict[item.PlayerID] = matchInfo;
@@ -175,6 +263,16 @@
                string name = userData["Name"].ToString();
                int addScore = int.Parse(userData["AddScore"].ToString());
                ulong fightPower = ulong.Parse(userData["FightPower"].ToString());
                uint serverID = 0;
                if (userData.ContainsKey("ServerID"))
                {
                    serverID = uint.Parse(userData["ServerID"].ToString());
                }
                uint cross = 0;
                if (userData.ContainsKey("Cross"))
                {
                    cross = uint.Parse(userData["Cross"].ToString());
                }
                var arenaGameRec = new ArenaGameRec
                {
@@ -189,7 +287,9 @@
                    Value8 = rec.Value8,
                    Name = name,
                    AddScore = addScore,
                    FightPower = fightPower
                    FightPower = fightPower,
                    ServerID = serverID,
                    Cross = cross
                };
                gameRecDict[recID].Add(arenaGameRec);
@@ -289,6 +389,8 @@
        seasonEndDate = new DateTime(sunday.Year, sunday.Month, sunday.Day, 23, 59, 59);
    }
    /// <summary>
    /// 根据recID获取按时间从大到小排序的List<ArenaGameRec>
    /// </summary>
@@ -313,6 +415,99 @@
            PlayerDatas.Instance.baseData.FightPower :
            FightPowerManager.Instance.GetTeamFightPower(TeamManager.Instance.GetTeamID(BattlePreSetType.Arena), false);
    }
    public readonly int DataMapID = 3;
    public bool IsOpenCrossServer()
    {
        bool isOpenCrossServer = CrossServerBaseManager.Instance.IsOpenCrossServer(DataMapID);
        return isOpenCrossServer;
    }
    public Dictionary<int, int[][]> GetCrossArenaAwardDict(int functionOrder)
    {
        return functionOrder switch
        {
            0 => dailyRankRewards,
            1 => seasonRankRewards,
            2 => GetCrossWeekRewards(),
            _ => new Dictionary<int, int[][]>()
        };
    }
    public Dictionary<int, int[][]> GetCrossWeekRewards()
    {
        var crossZoneInfo = CrossServerBaseManager.Instance.GetCrossZoneInfo(DataMapID);
        if (crossZoneInfo == null || crossZoneInfo.ServerIDList == null || crossRewardTemps.IsNullOrEmpty())
        {
            return new Dictionary<int, int[][]>();
        }
        int serverCount = crossZoneInfo.ServerIDList.Length;
        // 先对key进行排序,避免遍历顺序依赖
        var sortedKeys = crossRewardTemps.Keys.OrderBy(k => k).ToList();
        int templateID = 0;
        int matchedKey = 0;
        foreach (var key in sortedKeys)
        {
            if (key <= serverCount && key >= matchedKey)
            {
                matchedKey = key;
                templateID = crossRewardTemps[key];
            }
        }
        // 如果没有匹配的key(serverCount小于所有配置的key),取最小key对应的奖励
        if (templateID == 0 && sortedKeys.Count > 0)
        {
            var minKey = sortedKeys[0];
            templateID = crossRewardTemps[minKey];
        }
        if (templateID == 0) return new Dictionary<int, int[][]>();
        var rankList = ActBillboardAwardConfig.GetRankASortList(templateID);
        if (rankList.IsNullOrEmpty()) return new Dictionary<int, int[][]>();
        var result = new Dictionary<int, int[][]>();
        foreach (var rankA in rankList)
        {
            var config = ActBillboardAwardConfig.GetConfig(templateID, rankA);
            if (config?.AwardItemList != null)
            {
                result[rankA] = config.AwardItemList;
            }
        }
        return result;
    }
    /// <summary>
    /// 获得当前赛季的起止日期(跨服版本)。赛季从周一 00:00:00 开始,到周日 23:59:59 结束。
    /// 服务端定义周一为每周的第一天。
    /// </summary>
    /// <param name="zoneID">跨服zoneID,0表示本服时间,非0表示跨服时间</param>
    /// <param name="seasonStartDate">输出参数:赛季的起始日期(本周一 00:00:00)</param>
    /// <param name="seasonEndDate">输出参数:赛季的结束日期(本周日 23:59:59)</param>
    public void GetCrossCurrentSeasonDates(int zoneID, out DateTime seasonStartDate, out DateTime seasonEndDate)
    {
        DateTime now = TimeUtility.GetCommServerNow(zoneID);
        // 为了符合周一是一周第一天的计算标准,将周日视为一周的第7天。
        int currentDayOfWeek = (int)now.DayOfWeek;
        if (currentDayOfWeek == 0) // 如果是周日 (Sunday = 0)
        {
            currentDayOfWeek = 7;
        }
        DateTime monday = now.AddDays(-(currentDayOfWeek - 1));
        seasonStartDate = new DateTime(monday.Year, monday.Month, monday.Day, 0, 0, 0);
        DateTime sunday = seasonStartDate.AddDays(6);
        seasonEndDate = new DateTime(sunday.Year, sunday.Month, sunday.Day, 23, 59, 59);
    }
    public bool IsRobot(int playerID)
    {
        return RobotConfig.HasKey(playerID);
    }
}
@@ -327,6 +522,7 @@
    public ulong FightPower;        //战力
    public uint Face;        //基本脸型
    public uint FacePic;        //头像框
    public uint ServerID;
}
@@ -345,5 +541,7 @@
    public int AddScore;        //本次自己变更的积分,有正负
    public ulong FightPower;    //目标战力
    public int TitileId; //未来接入
    public uint ServerID;       //对手区服ID
    public uint Cross;          //是否跨服记录
}
Main/System/Arena/ArenaPlayerRankCell.cs
@@ -1,4 +1,3 @@
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
@@ -8,12 +7,23 @@
    [SerializeField] Text rankText;
    [SerializeField] Text rankValueText;    //排名比较内容
    [SerializeField] Text nameText;
    [SerializeField] Text serverText;
    [SerializeField] OfficialTitleCell officialTitleCell;
    [SerializeField] Button queryPlayerBtn; //后续添加点击查看玩家详情
    // rank 为0 代表玩家自己
    public void Display(int rankType, int rank, string valueFormat)
    {
        DisplayCross(rankType, rank, valueFormat, false);
    }
    public void DisplayCross(int rankType, int rank, string valueFormat)
    {
        DisplayCross(rankType, rank, valueFormat, true);
    }
    void DisplayCross(int rankType, int rank, string valueFormat, bool isCross)
    {
        RankData rankData = null;
        int viewPlayerId = (int)PlayerDatas.Instance.baseData.PlayerID;
@@ -29,11 +39,11 @@
                //取玩家自己的数据
                avatarCell.InitUI(AvatarHelper.GetAvatarModel((int)PlayerDatas.Instance.baseData.PlayerID,
                                                PlayerDatas.Instance.baseData.face,
                                                PlayerDatas.Instance.baseData.facePic)).Forget();
                                                PlayerDatas.Instance.baseData.facePic));
                rankText.text = Language.Get("L1045");
                rankValueText.text = ArenaManager.Instance.score.ToString();
                nameText.text = PlayerDatas.Instance.baseData.PlayerName;
                officialTitleCell.InitUI(PlayerDatas.Instance.baseData.realmLevel, PlayerDatas.Instance.baseData.TitleID).Forget();
                officialTitleCell.InitUI(PlayerDatas.Instance.baseData.realmLevel, PlayerDatas.Instance.baseData.TitleID);
                return;
            }
            rank = rankData.rank;
@@ -44,20 +54,30 @@
            avatarCell.SetActive(false);
            nameText.text = Language.Get("L1124");
            rankValueText.text = "0";//Language.Get("L1125");
            if (serverText != null)
                serverText.text = "";
        }
        else
        {
            viewPlayerId = (int)rankData.id;
            officialTitleCell.SetActive(true);
            officialTitleCell.InitUI((int)rankData.value1, (int)rankData.value2).Forget();
            officialTitleCell.InitUI((int)rankData.value1, (int)rankData.value2);
            avatarCell.SetActive(true);
            avatarCell.InitUI(AvatarHelper.GetAvatarModel((int)rankData.id, (int)rankData.value3, (int)rankData.value4)).Forget();
            avatarCell.SetOnLoaded(() =>
            avatarCell.InitUI(AvatarHelper.GetAvatarModel((int)rankData.id, (int)rankData.value3, (int)rankData.value4));
            // 跨服显示服务器名称
            if (isCross && serverText != null)
            {
                avatarCell.SetListener(() =>
                {
                    AvatarHelper.TryViewOtherPlayerInfo((int)rankData.id, viewPlayerLineupType: (int)BattlePreSetType.Arena);
                });
                if (ArenaManager.Instance.IsRobot((int)rankData.id))
                    serverText.text = ServerListCenter.Instance.GetServerName(UIHelper.GetServerIDByAccount(PlayerDatas.Instance.baseData.AccID));
                else
                    serverText.text = ServerListCenter.Instance.GetServerName(UIHelper.GetServerIDByAccount(rankData.name2));
            }
            avatarCell.SetListener(() =>
            {
                int serverID = (ArenaManager.Instance.IsOpenCrossServer() && rankData.id != PlayerDatas.Instance.baseData.PlayerID) ? UIHelper.GetServerIDByAccount(rankData.name2) : 0;
                AvatarHelper.TryViewOtherPlayerInfo((int)rankData.id, serverID, viewPlayerLineupType: (int)BattlePreSetType.Arena);
            });
            nameText.text = rankData.name1;
            rankValueText.text = string.Format(valueFormat, UIHelper.ReplaceLargeNum(rankData.cmpValue));
@@ -68,7 +88,8 @@
        {
            queryPlayerBtn.AddListener(() =>
            {
                AvatarHelper.TryViewOtherPlayerInfo(viewPlayerId, viewPlayerLineupType: (int)BattlePreSetType.Arena);
                int serverID = (ArenaManager.Instance.IsOpenCrossServer() && viewPlayerId != PlayerDatas.Instance.baseData.PlayerID) ? UIHelper.GetServerIDByAccount(rankData.name2) : 0;
                AvatarHelper.TryViewOtherPlayerInfo(viewPlayerId, serverID, viewPlayerLineupType: (int)BattlePreSetType.Arena);
            });
        }
    }
Main/System/Arena/ArenaPlayerTop3Cell.cs
@@ -1,17 +1,28 @@
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
public class ArenaPlayerTop3Cell : MonoBehaviour
{
    //[SerializeField] Model 显示NPC 武将模型
    [SerializeField] Text rankValueText;    //排名比较内容
    [SerializeField] Text nameText;
    [SerializeField] Text serverText;
    [SerializeField] OfficialTitleCell officialTitleCell;
    [SerializeField] Button queryPlayerBtn; //后续添加点击查看玩家详情
    [SerializeField] HorseController model;
    public void Display(int rankType, int rank, string valueFormat = "{0}")
    {
        DisplayCross(rankType, rank, valueFormat, false);
    }
    public void DisplayCross(int rankType, int rank, string valueFormat = "{0}")
    {
        DisplayCross(rankType, rank, valueFormat, true);
    }
    void DisplayCross(int rankType, int rank, string valueFormat, bool isCross)
    {
        var rankData = RankModel.Instance.GetRankDataByRank(rankType, rank);
        if (rankData == null)
@@ -19,16 +30,28 @@
            rankValueText.text = "0";//Language.Get("L1125");
            nameText.text = Language.Get("L1124");
            officialTitleCell.SetActive(false);
            if (serverText != null)
                serverText.text = "";
            return;
        }
        officialTitleCell.SetActive(true);
        rankValueText.text = string.Format(valueFormat, UIHelper.ReplaceLargeNum(rankData.cmpValue));
        nameText.text = rankData.name1;
        officialTitleCell.InitUI((int)rankData.value1, (int)rankData.value2).Forget();
        model.Create(HorseManager.Instance.GetOtherPlayerHorseSkinID((int)rankData.value6), (int)rankData.value5, 1).Forget();
        officialTitleCell.InitUI((int)rankData.value1, (int)rankData.value2);
        model.Create(HorseManager.Instance.GetOtherPlayerHorseSkinID((int)rankData.value6), (int)rankData.value5, 1);
        if (isCross && serverText != null)
        {
            if (ArenaManager.Instance.IsRobot((int)rankData.id))
                serverText.text = ServerListCenter.Instance.GetServerName(UIHelper.GetServerIDByAccount(PlayerDatas.Instance.baseData.AccID));
            else
                serverText.text = ServerListCenter.Instance.GetServerName(UIHelper.GetServerIDByAccount(rankData.name2));
        }
        queryPlayerBtn.SetListener(() =>
        {
            AvatarHelper.TryViewOtherPlayerInfo((int)rankData.id, viewPlayerLineupType: (int)BattlePreSetType.Arena);
            int serverID = (ArenaManager.Instance.IsOpenCrossServer() && rankData.id != PlayerDatas.Instance.baseData.PlayerID) ? UIHelper.GetServerIDByAccount(rankData.name2) : 0;
            AvatarHelper.TryViewOtherPlayerInfo((int)rankData.id, serverID, viewPlayerLineupType: (int)BattlePreSetType.Arena);
        });
    }
Main/System/Arena/ArenaRecordCell.cs
@@ -1,5 +1,4 @@
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using UnityEngine;
using System;
@@ -8,6 +7,8 @@
    [SerializeField] AvatarCell avatarCell;
    [SerializeField] TextEx txtName;
    [SerializeField] TextEx txtDate;
    [SerializeField] TextEx txtCrossDate;
    [SerializeField] TextEx txtServerName;
    [SerializeField] TextEx txtFightPoint;
    [SerializeField] TextEx txtState;
    [SerializeField] TextEx txtAdd;
@@ -38,7 +39,40 @@
            return;
        arenaGameRec = sortedList[index];
        imgType.SetSprite(arenaGameRec.Value2 == 1 ? "ArenaRecordTypeAtk" : "ArenaRecordTypeDef");
        txtDate.text = FormatTime(arenaGameRec.Time);
        // 跨服记录样式显示逻辑
        if (ArenaManager.Instance.IsOpenCrossServer())
        {
            // 跨服样式:txtDate隐藏,txtCrossDate和txtServerName显示
            txtDate.SetActive(false);
            txtCrossDate.SetActive(true);
            txtServerName.SetActive(true);
            if (arenaGameRec.Cross == 1)
            {
                // 跨服记录:显示跨服时间和跨服服务器
                txtCrossDate.text = FormatTime(arenaGameRec.Time);
                if (ArenaManager.Instance.IsRobot((int)arenaGameRec.Value3))
                    txtServerName.text = ServerListCenter.Instance.GetServerName(UIHelper.GetServerIDByAccount(PlayerDatas.Instance.baseData.AccID));
                else
                    txtServerName.text = ServerListCenter.Instance.GetServerName((int)arenaGameRec.ServerID);
            }
            else
            {
                // 本服记录:显示本服时间和本服服务器
                txtCrossDate.text = FormatTime(arenaGameRec.Time);
                txtServerName.text = ServerListCenter.Instance.GetServerName(UIHelper.GetServerIDByAccount(PlayerDatas.Instance.baseData.AccID));
            }
        }
        else
        {
            // 正常样式:txtDate显示,txtCrossDate和txtServerName隐藏
            txtDate.SetActive(true);
            txtDate.text = FormatTime(arenaGameRec.Time);
            txtCrossDate.SetActive(false);
            txtServerName.SetActive(false);
        }
        // true 已失效 false 未失效
        bool isTimeInvalid = ArenaManager.Instance.IsTimeInvalid(arenaGameRec.Time);
        // 发起攻击,打赢有积分,打输没有
@@ -65,17 +99,15 @@
            }
        }
        avatarCell.InitUI(AvatarHelper.GetAvatarModel((int)arenaGameRec.Value3, (int)arenaGameRec.Value5, (int)arenaGameRec.Value6)).Forget();
        avatarCell.SetOnLoaded(() =>
        avatarCell.InitUI(AvatarHelper.GetAvatarModel((int)arenaGameRec.Value3, (int)arenaGameRec.Value5, (int)arenaGameRec.Value6));
        avatarCell.SetListener(() =>
        {
            avatarCell.SetListener(() =>
            {
                AvatarHelper.TryViewOtherPlayerInfo((int)arenaGameRec.Value3, viewPlayerLineupType: (int)BattlePreSetType.Arena);
            });
            int serverID = (ArenaManager.Instance.IsOpenCrossServer() && arenaGameRec.Value3 != PlayerDatas.Instance.baseData.PlayerID) ? (int)arenaGameRec.ServerID : 0;
            AvatarHelper.TryViewOtherPlayerInfo((int)arenaGameRec.Value3, serverID, viewPlayerLineupType: (int)BattlePreSetType.Arena);
        });
        txtName.text = arenaGameRec.Name;
        txtFightPoint.text = UIHelper.ReplaceLargeArtNum(arenaGameRec.FightPower);
        officialTitleCell.InitUI(PlayerDatas.Instance.baseData.realmLevel, PlayerDatas.Instance.baseData.TitleID, 0.55f).Forget();
        officialTitleCell.InitUI(PlayerDatas.Instance.baseData.realmLevel, PlayerDatas.Instance.baseData.TitleID, 0.55f);
        imgMoneyIcon.SetIconWithMoneyType(ArenaManager.Instance.ChallengeMoneyType);
        txtNeedCount.text = ArenaManager.Instance.NeedChallengeMoneyCnt.ToString();
    }
Main/System/Arena/ArenaWin.cs
@@ -2,10 +2,18 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Cysharp.Threading.Tasks;
public class ArenaWin : UIBase
public class ArenaWin : FunctionsBaseWin
{
    [SerializeField] TextEx txtTip;
    [SerializeField] TextEx txtCrossTip;
    [SerializeField] Transform transLocalRank;
    [SerializeField] Transform transLocalButton;
    [SerializeField] Transform transLocalCrossButton;
    [SerializeField] ButtonEx btnCrossAward;
    [SerializeField] Button btnFunPresetCross;
    [SerializeField] ButtonEx btnRecord;
    [SerializeField] ButtonEx btnAward;
    [SerializeField] ButtonEx btnChallage;
@@ -16,7 +24,21 @@
    [SerializeField] ArenaPlayerRankCell myRankCell;
    [SerializeField] ArenaChallengeVoucher voucher;
    [SerializeField] Button funPresetBtn;
    //跨服排行
    [SerializeField] Transform transCrossRank;
    [SerializeField] ButtonEx btnRecordCross;
    [SerializeField] ButtonEx btnAwardCross;
    [SerializeField] ButtonEx btnChallageCross;
    [SerializeField] RedpointBehaviour rpChallageCross;
    [SerializeField] List<ArenaPlayerTop3Cell> playerTop3CellsCross;
    [SerializeField] ScrollerController scrollerControllerCross;
    [SerializeField] ArenaPlayerRankCell myRankCellCross;
    [SerializeField] ArenaChallengeVoucher voucherCross;
    [SerializeField] Button funPresetBtnCross;
    [SerializeField] Button serversBtn;
    [HideInInspector] public int groupValue1 = 0;   //一般用于跨服
    [HideInInspector] public int groupValue2 = 0;   //一般用于跨服
    [HideInInspector] public string valueFormat = "{0}";
@@ -24,42 +46,162 @@
    protected override void InitComponent()
    {
        base.InitComponent();
        btnAward.SetListener(() => UIManager.Instance.OpenWindowAsync<ArenaAwardWin>().Forget());
        btnAward.SetListener(() =>
        {
            if (ArenaManager.Instance.IsOpenCrossServer())
                UIManager.Instance.OpenWindow<ArenaCrossAwardWin>();
            else
                UIManager.Instance.OpenWindow<ArenaAwardWin>();
        });
        btnRecord.SetListener(() =>
        {
            ArenaManager.Instance.SendViewGameRecPack();
            UIManager.Instance.OpenWindowAsync<ArenaRecordWin>().Forget();
            UIManager.Instance.OpenWindow<ArenaRecordWin>();
        });
        btnChallage.SetListener(() =>
        {
            ArenaManager.Instance.SendArenaMatch();
            UIManager.Instance.OpenWindowAsync<ArenaChallengeWin>().Forget();
            UIManager.Instance.OpenWindow<ArenaChallengeWin>();
        });
        funPresetBtn.AddListener(()=>
        funPresetBtn.AddListener(() =>
        {
            FuncPresetManager.Instance.ClickBattlePreset((int)BattlePreSetType.Arena);
        });
        btnCrossAward.SetListener(() =>
        {
            if (ArenaManager.Instance.IsOpenCrossServer())
                UIManager.Instance.OpenWindow<ArenaCrossAwardWin>();
            else
                UIManager.Instance.OpenWindow<ArenaAwardWin>();
        });
        btnFunPresetCross.AddListener(() =>
        {
            FuncPresetManager.Instance.ClickBattlePreset((int)BattlePreSetType.Arena);
        });
        // 跨服按钮监听器
        btnAwardCross.SetListener(() =>
        {
            UIManager.Instance.OpenWindow<ArenaCrossAwardWin>();
        });
        btnRecordCross.SetListener(() =>
        {
            ArenaManager.Instance.SendViewGameRecPack();
            UIManager.Instance.OpenWindow<ArenaRecordWin>();
        });
        btnChallageCross.SetListener(() =>
        {
            ArenaManager.Instance.SendArenaMatch();
            UIManager.Instance.OpenWindow<ArenaChallengeWin>();
        });
        funPresetBtnCross.AddListener(() =>
        {
            FuncPresetManager.Instance.ClickBattlePreset((int)BattlePreSetType.Arena);
        });
        serversBtn.SetListener(() =>
        {
            var crossZoneInfo = CrossServerBaseManager.Instance.GetCrossZoneInfo(ArenaManager.Instance.DataMapID);
            if (crossZoneInfo == null) return;
            var serverIDList = new List<int>(Array.ConvertAll(crossZoneInfo.ServerIDList, x => (int)x));
            UIHelper.ShowServersPanel(serverIDList);
        });
    }
    protected override void OnPreOpen()
    {
        base.OnPreOpen();
        RankModel.Instance.ResetQueryParam();
        RankModel.Instance.QueryRankByPage(ArenaManager.Instance.rankType, watchID: (int)PlayerDatas.Instance.baseData.PlayerID);
        rpChallage.redpointId = ArenaManager.Instance.GetRedPonitId(1);
    }
        // 在base.OnPreOpen()之前设置functionOrder,避免被父类传入参数覆盖
        bool isOpenCrossServer = ArenaManager.Instance.IsOpenCrossServer();
        if (isOpenCrossServer)
        {
            functionOrder = 1;  // 跨服排行
        }
        else
        {
            functionOrder = 0;  // 本服排行
        }
    protected override void NextFrameAfterOpen()
    {
        base.OnPreOpen();
        rpChallage.redpointId = ArenaManager.Instance.GetRedPonitId(1);
        rpChallageCross.redpointId = ArenaManager.Instance.GetRedPonitId(1);
        RankModel.Instance.onRankRefresh += OnRankRefresh;
        scrollerController.OnRefreshCell += OnRefreshCell;
        scrollerControllerCross.OnRefreshCell += OnRefreshCellCross;
        ArenaManager.Instance.OnArenaMatchListEvent += OnArenaMatchListEvent;
        ArenaManager.Instance.OnUpdateArenaPlayerInfo += OnUpdateArenaPlayerInfo;
        ArenaManager.Instance.OnUpdateGameRecInfo += OnUpdateGameRecInfo;
        PlayerDatas.Instance.playerDataRefreshEvent += PlayerDataRefresh;
        FuncOpen.Instance.OnFuncStateChangeEvent += OnFuncStateChange;
        ShowRankByFunctionOrder();
        txtTip.SetActive(!isOpenCrossServer);
        txtCrossTip.SetActive(isOpenCrossServer);
        for (int i = 0; i < tabButtons.Length; i++)
        {
            tabButtons[i].SetActive(isOpenCrossServer);
        }
        RankModel.Instance.ResetQueryParam();
        if (isOpenCrossServer)
        {
            var crossZoneInfo = CrossServerBaseManager.Instance.GetCrossZoneInfo(ArenaManager.Instance.DataMapID);
            if (crossZoneInfo != null)
            {
                RankModel.Instance.QueryRankByPage(ArenaManager.Instance.corssRankType, groupValue1: (int)crossZoneInfo.ZoneID, crossServerID: (int)crossZoneInfo.CrossServerID, watchID: (int)PlayerDatas.Instance.baseData.PlayerID);
            }
        }
        else
        {
            RankModel.Instance.QueryRankByPage(ArenaManager.Instance.rankType, watchID: (int)PlayerDatas.Instance.baseData.PlayerID);
        }
        Display();
    }
    protected override void OpenSubUIByTabIndex()
    {
        ShowRankByFunctionOrder();
        RankModel.Instance.ResetQueryParam();
        // 重新查询对应排行
        bool isOpenCrossServer = ArenaManager.Instance.IsOpenCrossServer();
        if (functionOrder == 0 && isOpenCrossServer)
        {
            // 本服排行
            RankModel.Instance.QueryRankByPage(ArenaManager.Instance.rankType, watchID: (int)PlayerDatas.Instance.baseData.PlayerID);
        }
        else if (functionOrder == 1 && isOpenCrossServer)
        {
            // 跨服排行
            var crossZoneInfo = CrossServerBaseManager.Instance.GetCrossZoneInfo(ArenaManager.Instance.DataMapID);
            if (crossZoneInfo != null)
            {
                RankModel.Instance.QueryRankByPage(ArenaManager.Instance.corssRankType, groupValue1: (int)crossZoneInfo.ZoneID, crossServerID: (int)crossZoneInfo.CrossServerID, watchID: (int)PlayerDatas.Instance.baseData.PlayerID);
            }
        }
    }
    void ShowRankByFunctionOrder()
    {
        if (functionOrder == 0)
        {
            // 本服排行
            transLocalRank.SetActive(true);
            bool isOpenCrossServer = ArenaManager.Instance.IsOpenCrossServer();
            transLocalButton.SetActive(!isOpenCrossServer);
            transLocalCrossButton.SetActive(isOpenCrossServer);
            transCrossRank.SetActive(false);
        }
        else
        {
            // 跨服排行
            transLocalRank.SetActive(false);
            transCrossRank.SetActive(true);
        }
    }
    protected override void OnPreClose()
@@ -67,6 +209,7 @@
        base.OnPreClose();
        RankModel.Instance.onRankRefresh -= OnRankRefresh;
        scrollerController.OnRefreshCell -= OnRefreshCell;
        scrollerControllerCross.OnRefreshCell -= OnRefreshCellCross;
        ArenaManager.Instance.OnArenaMatchListEvent -= OnArenaMatchListEvent;
        ArenaManager.Instance.OnUpdateArenaPlayerInfo -= OnUpdateArenaPlayerInfo;
        ArenaManager.Instance.OnUpdateGameRecInfo -= OnUpdateGameRecInfo;
@@ -103,6 +246,18 @@
        RankModel.Instance.ListenRankPage(ArenaManager.Instance.rankType, cell.index, groupValue1, groupValue2);
    }
    void OnRefreshCellCross(ScrollerDataType type, CellView cell)
    {
        var crossZoneInfo = CrossServerBaseManager.Instance.GetCrossZoneInfo(ArenaManager.Instance.DataMapID);
        int zoneID = crossZoneInfo != null ? (int)crossZoneInfo.ZoneID : 0;
        int crossServerID = crossZoneInfo != null ? (int)crossZoneInfo.CrossServerID : 0;
        var _cell = cell.GetComponent<ArenaPlayerRankCell>();
        _cell.DisplayCross(ArenaManager.Instance.corssRankType, cell.index + 1, valueFormat);
        RankModel.Instance.ListenRankPage(ArenaManager.Instance.corssRankType, cell.index, zoneID, 0, crossServerID);
    }
    private void OnUpdateArenaPlayerInfo()
    {
        Display();
@@ -127,6 +282,13 @@
        DisplayDeployTroop();
        funPresetBtn.SetActive(FuncPresetManager.Instance.IsPreShow());
        // 跨服显示
        voucherCross.Display();
        CreateScrollerCross();
        DisplayMyRankCross();
        DisplayTop3Cross();
        funPresetBtnCross.SetActive(FuncPresetManager.Instance.IsPreShow());
    }
    void CreateScroller()
@@ -140,9 +302,25 @@
        scrollerController.Restart();
    }
    void CreateScrollerCross()
    {
        scrollerControllerCross.Refresh();
        var cnt = RankModel.Instance.GetRankShowMaxCnt(ArenaManager.Instance.corssRankType);
        for (int i = 3; i < cnt; i++)
        {
            scrollerControllerCross.AddCell(ScrollerDataType.Header, i);
        }
        scrollerControllerCross.Restart();
    }
    void DisplayMyRank()
    {
        myRankCell.Display(ArenaManager.Instance.rankType, 0, ArenaManager.Instance.score.ToString());
    }
    void DisplayMyRankCross()
    {
        myRankCellCross.DisplayCross(ArenaManager.Instance.corssRankType, 0, ArenaManager.Instance.score.ToString());
    }
    void DisplayTop3()
@@ -153,12 +331,27 @@
        }
    }
    void DisplayTop3Cross()
    {
        for (int i = 0; i < playerTop3CellsCross.Count; i++)
        {
            playerTop3CellsCross[i].DisplayCross(ArenaManager.Instance.corssRankType, i + 1);
        }
    }
    void OnRankRefresh(int type)
    {
        if (type != ArenaManager.Instance.rankType)
            return;
        DisplayTop3();
        scrollerController.m_Scorller.RefreshActiveCellViews();
        DisplayMyRank();
        if (type == ArenaManager.Instance.rankType)
        {
            DisplayTop3();
            scrollerController.m_Scorller.RefreshActiveCellViews();
            DisplayMyRank();
        }
        else if (type == ArenaManager.Instance.corssRankType)
        {
            DisplayTop3Cross();
            scrollerControllerCross.m_Scorller.RefreshActiveCellViews();
            DisplayMyRankCross();
        }
    }
}
Main/System/BillboardRank/PlayerRankCell.cs
@@ -32,6 +32,7 @@
        RankData rankData = null;
        int viewPlayerId = (int)PlayerDatas.Instance.baseData.PlayerID;
        int sid = 0;
        if (rank != 0)
        {
            rankData = RankModel.Instance.GetRankDataByRank(rankType, rank);
@@ -68,15 +69,17 @@
            avatarCell.InitUI(AvatarHelper.GetAvatarModel((int)rankData.id, (int)rankData.value3, (int)rankData.value4)).Forget();
            viewPlayerId = (int)rankData.id;
            nameText.text = rankData.name1;
            rankValueText.text = RankModel.Instance.GetCmpValueStr(rankType, rankData.cmpValue); ;
            rankValueText.text = RankModel.Instance.GetCmpValueStr(rankType, rankData.cmpValue);
            sid = UIHelper.GetServerIDByAccount(rankData.name2);
        }
        rankText.text = rank.ToString();
        if (queryPlayerBtn != null)
        {
            queryPlayerBtn.AddListener(() =>
            {
                AvatarHelper.TryViewOtherPlayerInfo(viewPlayerId);
                AvatarHelper.TryViewOtherPlayerInfo(viewPlayerId, sid);
            });
        }
Main/System/BillboardRank/PlayerTop3Cell.cs
@@ -48,7 +48,7 @@
        model.Create(HorseManager.Instance.GetOtherPlayerHorseSkinID((int)rankData.value6), (int)rankData.value5, rank == 1 ? 1f : 0.8f).Forget();
        queryPlayerBtn.SetListener(() =>
        {
            AvatarHelper.TryViewOtherPlayerInfo((int)rankData.id);
            AvatarHelper.TryViewOtherPlayerInfo((int)rankData.id, UIHelper.GetServerIDByAccount(rankData.name2));
        });
    }
Main/System/BillboardRank/RankModel.cs
@@ -117,7 +117,7 @@
        var pak = new CA130_tagCMViewBillboard();
        pak.Type = (byte)type;
        pak.GroupValue1 = (byte)groupValue1;
        pak.GroupValue1 = (uint)groupValue1;
        pak.GroupValue2 = (uint)groupValue2;
        pak.StartIndex = (ushort)startIndex;  //排名从0开始
        pak.ViewCnt = (byte)count;
Main/System/BoneField/AdsManager.cs
@@ -189,6 +189,9 @@
            case 6:
                SendGetReward(ADID);
                break;
            case 7:
                SendGetReward(ADID);
                break;
        }
    }
Main/System/CrossServer/CrossServerBaseManager.cs
@@ -8,6 +8,10 @@
public class CrossServerBaseManager : GameSystemManager<CrossServerBaseManager>
{
    public Dictionary<int, CrossZoneInfo> crossZoneInfoDict = new Dictionary<int, CrossZoneInfo>();
    // 跨服状态更新事件,参数为mapID
    public event Action<int> OnCrossZoneInfoUpdateEvent;
    public override void Init()
    {
        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEventOnRelogin += OnBeforePlayerDataInitialize;
@@ -32,7 +36,8 @@
            ServerIDList = netPack.ServerIDList,
            CrossServerID = netPack.CrossServerID
        };
        OnCrossZoneInfoUpdateEvent?.Invoke((int)netPack.MapID);
    }
    // 没有数据代表不在跨服中,群英有个特殊约定zoneid等于0代表结算中
Main/System/FestivalActivity.meta
New file
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5533b52633741964d91069149670dd58
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/FestivalActivityCheckInCell.cs
New file
@@ -0,0 +1,92 @@
using UnityEngine;
public class FestivalActivityCheckInCell : MonoBehaviour
{
    [SerializeField] ButtonEx clickButton;
    [SerializeField] ImageEx darkImage;
    [SerializeField] ImageEx lightImage;
    [SerializeField] TextEx dayText;
    [SerializeField] ItemCell[] itemCells;
    [SerializeField] UIEffectPlayer[] uiEffectPlayers;
    [SerializeField] UIEffectPlayer bgUIEffectPlayer;
    [SerializeField] ImageEx[] haveImages;
    [SerializeField] Transform imgMask;
    FestivalActivityCheckInManager manager => FestivalActivityCheckInManager.Instance;
    private int currentState;
    public void Display(int templateID, int dayNum)
    {
        bgUIEffectPlayer.Stop();
        for (int i = 0; i < uiEffectPlayers.Length; i++)
        {
            uiEffectPlayers[i].Stop();
        }
        for (int i = 0; i < haveImages.Length; i++)
        {
            haveImages[i].SetActive(false);
        }
        var config = ActSignAwardConfig.GetConfig(templateID, dayNum);
        if (config == null) return;
        if (config.SignAwardItemList.IsNullOrEmpty()) return;
        currentState = manager.GetCheckInState(dayNum);
        imgMask.SetActive(currentState == 2);
        darkImage.SetActive(currentState != 1);
        lightImage.SetActive(currentState == 1);
        if (currentState == 1)
        {
            bgUIEffectPlayer.Play();
            for (int i = 0; i < uiEffectPlayers.Length; i++)
            {
                if (i < config.SignAwardItemList.Length)
                {
                    uiEffectPlayers[i].Play();
                }
            }
        }
        if (currentState == 2)
        {
            for (int i = 0; i < haveImages.Length; i++)
            {
                if (i < config.SignAwardItemList.Length)
                {
                    haveImages[i].SetActive(true);
                }
            }
        }
        dayText.text = Language.Get($"SignDay{dayNum}");
        for (int i = 0; i < itemCells.Length; i++)
        {
            int index = i;
            if (i < config.SignAwardItemList.Length)
            {
                itemCells[i].SetActive(true);
                itemCells[i].Init(new ItemCellModel(config.SignAwardItemList[i][0], false, config.SignAwardItemList[i][1]));
                itemCells[i].button.AddListener(() =>
                {
                    if (currentState == 1)
                    {
                        manager.SendGetCheckInReward();
                    }
                    else
                    {
                        ItemTipUtility.Show(config.SignAwardItemList[index][0]);
                    }
                });
            }
            else
            {
                itemCells[i].SetActive(false);
            }
        }
        clickButton.SetListener(() => manager.SendGetCheckInReward());
    }
}
Main/System/FestivalActivity/FestivalActivityCheckInCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 466abe185fe4c1e4bbd404360dfe9e42
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/FestivalActivityCheckInManager.cs
New file
@@ -0,0 +1,191 @@
using System;
public class FestivalActivityCheckInManager : GameSystemManager<FestivalActivityCheckInManager>, IOpenServerActivity
{
    public readonly int ActNum = 30;
    public override void Init()
    {
        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEventOnRelogin += OnBeforePlayerDataInitializeEventOnRelogin;
        OperationTimeHepler.Instance.operationTimeUpdateEvent += OperationTimeUpdateEvent;
        OperationTimeHepler.Instance.operationStartEvent += OperationStartEvent;
        OperationTimeHepler.Instance.operationEndEvent += OperationEndEvent;
        OperationTimeHepler.Instance.operationAdvanceEvent += OperationAdvanceEvent;
        FuncOpen.Instance.OnFuncStateChangeEvent += OnFuncStateChangeEvent;
        GeneralActInfoManager.Instance.OnUpdateActSignInfosEvent += OnUpdateActSignInfosEvent;
        TimeMgr.Instance.OnDayEvent += OnDayEvent;
    }
    public override void Release()
    {
        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEventOnRelogin -= OnBeforePlayerDataInitializeEventOnRelogin;
        OperationTimeHepler.Instance.operationTimeUpdateEvent -= OperationTimeUpdateEvent;
        OperationTimeHepler.Instance.operationStartEvent -= OperationStartEvent;
        OperationTimeHepler.Instance.operationEndEvent -= OperationEndEvent;
        OperationTimeHepler.Instance.operationAdvanceEvent -= OperationAdvanceEvent;
        FuncOpen.Instance.OnFuncStateChangeEvent -= OnFuncStateChangeEvent;
        GeneralActInfoManager.Instance.OnUpdateActSignInfosEvent -= OnUpdateActSignInfosEvent;
        TimeMgr.Instance.OnDayEvent -= OnDayEvent;
    }
    private void OnBeforePlayerDataInitializeEventOnRelogin()
    {
    }
    private void OnDayEvent()
    {
        UpdateRedPoint();
    }
    private void OnUpdateActSignInfosEvent(int arg1, int arg2)
    {
        UpdateRedPoint();
    }
    private void OnFuncStateChangeEvent(int obj)
    {
        if (obj != (int)FuncOpenEnum.FestivalActivity)
            return;
        UpdateRedPoint();
    }
    public const int activityType = (int)OpenServerActivityCenter.ActivityType.AT_DateActivity;
    public const int activityID = (int)NewDayActivityID.FestivalActivityCheckInAct;
    public static OperationType operaType = OperationType.FestivalActivity_CheckIn;
    public Redpoint redPoint = new Redpoint(MainRedDot.FestivalActivityRepoint,
        FestivalActivityManager.Instance.GetRedPointId(FestivalActivityRepointType.CheckIn));
    public bool IsOpen => OperationTimeHepler.Instance.SatisfyOpenCondition(operaType);
    public bool IsAdvance => OperationTimeHepler.Instance.SatisfyAdvanceCondition(operaType);
    public bool priorityOpen => redPoint.state == RedPointState.Simple;
    public event Action<int> onStateUpdate;
    private void OperationTimeUpdateEvent(OperationType type)
    {
        if (type == operaType)
        {
            UpdateRedPoint();
        }
    }
    private void OperationStartEvent(OperationType type, int state)
    {
        if (type == operaType && state == 0)
        {
            UpdateRedPoint();
            onStateUpdate?.Invoke(activityID);
        }
    }
    private void OperationEndEvent(OperationType type, int state)
    {
        if (type == operaType)
        {
            UpdateRedPoint();
            onStateUpdate?.Invoke(activityID);
        }
    }
    private void OperationAdvanceEvent(OperationType type)
    {
        if (type == operaType)
        {
            UpdateRedPoint();
            onStateUpdate?.Invoke(activityID);
        }
    }
    public void UpdateRedPoint()
    {
        redPoint.state = RedPointState.None;
        if (!FuncOpen.Instance.IsFuncOpen((int)FuncOpenEnum.FestivalActivity))
            return;
        if (!IsOpen)
            return;
        if (HasCheckInCanHave())
        {
            redPoint.state = RedPointState.Simple;
        }
    }
    public OperationCheckInActivityInfo GetOperationCheckInInfo()
    {
        OperationTimeHepler.Instance.TryGetOperation(operaType, out OperationCheckInActivityInfo act);
        return act;
    }
    public bool GetActInfo(out OperationCheckInActivityInfo act, out ActSignConfig config)
    {
        config = null;
        act = GetOperationCheckInInfo();
        if (act == null)
            return false;
        config = ActSignConfig.Get(act.CfgID);
        return config != null;
    }
    private int GetNowDayNum()
    {
        var act = GetOperationCheckInInfo();
        if (act == null) return 0;
        int dayNum = act.IndexOfDays(TimeUtility.ServerNow);
        return dayNum < 0 ? 0 : dayNum + 1;
    }
    private bool IsCheckInGridUnlock(int gridDayNum)
    {
        int nowDayNum = GetNowDayNum();
        if (nowDayNum <= 0) return false;
        return nowDayNum >= gridDayNum;
    }
    /// <summary>
    /// 0-未解锁 1-可签 2-已签
    /// </summary>
    public int GetCheckInState(int gridDayNum)
    {
        // 签到活动的ActType默认为0
        if (GeneralActInfoManager.Instance.IsDaySigned(0, ActNum, gridDayNum)) return 2;
        if (IsCheckInGridUnlock(gridDayNum)) return 1;
        return 0;
    }
    public void SendGetCheckInReward()
    {
        // 签到活动的ActType默认为0
        GeneralActInfoManager.Instance.SendGetSignReward(0, ActNum);
    }
    public bool HasCheckInCanHave()
    {
        if (!GetActInfo(out var act, out var config))
            return false;
        int templateID = config.SignTempID;
        var list = ActSignAwardConfig.GetDayNumSortList(templateID);
        if (list == null) return false;
        for (int i = 0; i < list.Count; i++)
        {
            int dayNum = list[i];
            int state = GetCheckInState(dayNum);
            if (state == 1) return true;
        }
        return false;
    }
    public void GetActTimeStr(TextEx timeText, string key = "TimeRush05")
    {
        var act = GetOperationCheckInInfo();
        if (act == null)
        {
            timeText.text = Language.Get("OSActivity6");
            return;
        }
        timeText.text = Language.Get(key, TimeUtility.SecondsToShortDHMS(act.GetResetSurplusTime()));
    }
}
Main/System/FestivalActivity/FestivalActivityCheckInManager.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 36e836fe2fdb08041955a6e15c6346ef
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/FestivalActivityCheckInWin.cs
New file
@@ -0,0 +1,63 @@
using UnityEngine;
public class FestivalActivityCheckInWin : UIBase
{
    [SerializeField] ButtonEx closeButton;
    [SerializeField] TextEx timeText;
    [SerializeField] FestivalActivityCheckInCell[] cells;
    FestivalActivityCheckInManager manager => FestivalActivityCheckInManager.Instance;
    protected override void InitComponent()
    {
        closeButton.SetListener(CloseWindow);
    }
    protected override void OnPreOpen()
    {
        GeneralActInfoManager.Instance.OnUpdateActSignInfosEvent += OnUpdateActSignInfosEvent;
        TimeMgr.Instance.OnDayEvent += OnDayEvent;
        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
        Display();
    }
    protected override void OnPreClose()
    {
        GeneralActInfoManager.Instance.OnUpdateActSignInfosEvent -= OnUpdateActSignInfosEvent;
        TimeMgr.Instance.OnDayEvent -= OnDayEvent;
        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
    }
    private void OnDayEvent()
    {
        Display();
    }
    private void OnUpdateActSignInfosEvent(int arg1, int arg2)
    {
        Display();
    }
    private void OnSecondEvent()
    {
        manager.GetActTimeStr(timeText);
    }
    private void Display()
    {
        if (!manager.GetActInfo(out var act, out var config))
            return;
        int templateID = config.SignTempID;
        var list = ActSignAwardConfig.GetDayNumSortList(templateID);
        if (list == null) return;
        for (int i = 0; i < cells.Length; i++)
        {
            if (i < list.Count)
            {
                cells[i].SetActive(true);
                cells[i].Display(templateID, list[i]);
            }
            else
            {
                cells[i].SetActive(false);
            }
        }
        OnSecondEvent();
    }
}
Main/System/FestivalActivity/FestivalActivityCheckInWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a837dc5f21722df49bca4419569b24bb
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/FestivalActivityGiftCell.cs
New file
@@ -0,0 +1,227 @@
using System.Collections.Generic;
using UnityEngine;
public class FestivalActivityGiftCell : MonoBehaviour
{
    [SerializeField] ImageEx vipImage;
    [SerializeField] TextEx vipText;
    [SerializeField] OutlineEx vipTextOutline;
    [SerializeField] ImageEx rateImage;
    [SerializeField] TextEx rateText;
    [SerializeField] ItemCell[] itemCells;
    [SerializeField] TextEx titleText;
    [SerializeField] ButtonEx buyButton;
    [SerializeField] ImageEx buyImage;
    [SerializeField] TextEx buyText;
    [SerializeField] TextEx buyText1;
    [SerializeField] ImageEx moneyIconImage;
    [SerializeField] ImageEx adImage;
    [SerializeField] TextEx limitCountText;
    [SerializeField] ImageEx redImage;
    FestivalActivityManager manager => FestivalActivityManager.Instance;
    StoreModel storeModel => StoreModel.Instance;
    public void Display(int index, List<FestivalActivityGiftItem> giftItems)
    {
        if (giftItems.IsNullOrEmpty() || index < 0 || index >= giftItems.Count) return;
        FestivalActivityGiftItem item = giftItems[index];
        if (item.type == 0)
        {
            DisplayStore(item.id);
            return;
        }
        if (item.type == 1)
        {
            DisplayAD(item.id);
            return;
        }
        DisplayCTG(item.id);
    }
    private void DisplayCTG(int ctgId)
    {
        redImage.SetActive(false);
        buyText.SetActive(true);
        buyText1.SetActive(false);
        moneyIconImage.SetActive(false);
        adImage.SetActive(false);
        rateImage.SetActive(true);
        if (!RechargeManager.Instance.TryGetOrderInfo(ctgId, out var orderConfig)) return;
        if (!RechargeManager.Instance.TryGetRechargeCount(ctgId, out var rechargeCount)) return;
        if (!CTGConfig.HasKey(ctgId)) return;
        if (!RechargeManager.Instance.TryGetRechargeItem(ctgId, out var rechargeItemList)) return;
        CTGConfig config = CTGConfig.Get(ctgId);
        vipImage.SetActive(config.VipLevel > 0);
        if (config.VipLevel > 0)
        {
            vipImage.SetSprite($"VipLevel{config.VipLevel}");
            vipText.text = Language.Get($"VipLevelInfo{config.VipLevel}");
            vipText.color = InvestModel.Instance.GetTextColor(config.VipLevel);
            vipTextOutline.OutlineColor = InvestModel.Instance.GetOutlineColor(config.VipLevel);
        }
        rateImage.SetActive(true);
        rateText.text = Language.Get("DailySpecials07", config.Percentage);
        bool isCanBuy = manager.IsCanBuy(ctgId, out bool isNoLimitBuy, out int nowBuyCnt, out int maxBuyCnt);
        titleText.text = config.Title;
        buyImage.SetSprite(isCanBuy ? "DailySpecialsBuy1" : "DailySpecialsBuy2");
        buyText.text = !isCanBuy ? Language.Get("storename11") : Language.Get("PayMoneyNum", UIHelper.GetMoneyFormat(orderConfig.PayRMBNumOnSale));
        limitCountText.SetActive(!isNoLimitBuy && maxBuyCnt > 0);
        if (!isNoLimitBuy && maxBuyCnt > 0)
        {
            limitCountText.text = Language.Get("HeroDebut39", UIHelper.AppendColor(nowBuyCnt >= maxBuyCnt ? TextColType.Red : TextColType.LightGreen, Mathf.Max(0, maxBuyCnt - nowBuyCnt).ToString()));
        }
        buyButton.interactable = isCanBuy;
        buyButton.SetListener(() =>
        {
            if (config.VipLevel > 0 && !FuncOpen.Instance.IsFuncOpen((int)FuncOpenEnum.PrivilegeCard))
            {
                SysNotifyMgr.Instance.ShowTip("MinggeAuto8");
                return;
            }
            if (config.VipLevel == 1 && !InvestModel.Instance.IsInvested(InvestModel.monthCardType))
            {
                SysNotifyMgr.Instance.ShowTip("MinggeAuto5");
                UIManager.Instance.OpenWindow<PrivilegeCardWin>();
                return;
            }
            if (config.VipLevel == 2 && !InvestModel.Instance.IsInvested(InvestModel.foreverCardType))
            {
                SysNotifyMgr.Instance.ShowTip("MinggeAuto7");
                UIManager.Instance.OpenWindow<PrivilegeCardWin>();
                return;
            }
            RechargeManager.Instance.CTG(ctgId);
        });
        for (int i = 0; i < itemCells.Length; i++)
        {
            var itemBaisc = itemCells[i];
            if (i < rechargeItemList.Count)
            {
                var itemInfo = rechargeItemList[i];
                itemBaisc.SetActive(true);
                itemBaisc.Init(new ItemCellModel((int)itemInfo.id, false, itemInfo.countEx));
                itemBaisc.button.AddListener(() =>
                {
                    ItemTipUtility.Show((int)itemInfo.id);
                });
            }
            else
            {
                itemBaisc.SetActive(false);
            }
        }
    }
    private void DisplayStore(int id)
    {
        rateImage.SetActive(false);
        vipImage.SetActive(false);
        if (!StoreConfig.HasKey(id)) return;
        StoreConfig storeConfig = StoreConfig.Get(id);
        int remainNum;
        storeModel.TryGetIsSellOut(storeConfig, out remainNum);
        bool isFree = manager.IsFreeShop(id);
        titleText.text = storeConfig.Name;
        limitCountText.SetActive(!isFree);
        limitCountText.text = Language.Get("HeroDebut39", UIHelper.AppendColor(remainNum == 0 ? TextColType.Red : TextColType.LightGreen, Mathf.Max(0, remainNum).ToString(), true));
        bool isCanBuy = manager.IsNoSellOutShopID(id);
        redImage.SetActive(isFree && isCanBuy);
        buyText.SetActive(isFree || !isCanBuy);
        buyText.text = isFree ? Language.Get("L1127") : Language.Get("storename11");
        buyText1.SetActive(!isFree && isCanBuy);
        buyText1.text = UIHelper.GetMoneyFormat(storeConfig.MoneyNum);
        adImage.SetActive(false);
        moneyIconImage.SetActive(!isFree && isCanBuy);
        moneyIconImage.SetIconWithMoneyType(1);
        buyImage.SetSprite(isCanBuy ? "DailySpecialsBuy1" : "DailySpecialsBuy2");
        buyButton.interactable = isCanBuy;
        buyButton.SetListener(() =>
        {
            storeModel.SendBuyShopItemWithPopCheck(storeConfig, 1, (int)BuyStoreItemCheckType.ActGift);
        });
        var items = storeModel.GetShopItemlistByIndex(storeConfig);
        for (int i = 0; i < itemCells.Length; i++)
        {
            var itemBaisc = itemCells[i];
            if (i < items.Count)
            {
                var itemInfo = items[i];
                itemBaisc.SetActive(true);
                itemBaisc.Init(new ItemCellModel(itemInfo.itemId, false, itemInfo.count));
                itemBaisc.button.AddListener(() =>
                {
                    ItemTipUtility.Show(itemInfo.itemId);
                });
            }
            else
            {
                itemBaisc.SetActive(false);
            }
        }
    }
    private void DisplayAD(int ADID)
    {
        rateImage.SetActive(false);
        vipImage.SetActive(false);
        ADAwardConfig config = ADAwardConfig.Get(ADID);
        if (config == null) return;
        bool isCanBuy = manager.IsAdAwardCanReceive(ADID);
        int receivedCnt = AdsManager.Instance.GetADCntByADID(ADID);
        titleText.text = config.Name;
        limitCountText.SetActive(true);
        limitCountText.text = Language.Get("HeroDebut39", UIHelper.AppendColor(!isCanBuy ? TextColType.Red : TextColType.LightGreen, Mathf.Max(config.ADCntMax - receivedCnt, 0).ToString()));
        redImage.SetActive(isCanBuy);
        buyText.SetActive(false);
        buyText1.SetActive(true);
        buyText1.text = Language.Get("L1127");
        moneyIconImage.SetActive(false);
        adImage.SetActive(true);
        adImage.gray = !isCanBuy;
        buyImage.SetSprite(isCanBuy ? "DailySpecialsBuy1" : "DailySpecialsBuy2");
        buyButton.interactable = isCanBuy;
        buyButton.SetListener(() =>
        {
            AdsManager.Instance.GetAdsAward(ADID);
        });
        var items = config.ADAwardItemList;
        for (int i = 0; i < itemCells.Length; i++)
        {
            var itemBaisc = itemCells[i];
            if (i < items.Length)
            {
                var itemInfo = items[i];
                itemBaisc.SetActive(true);
                itemBaisc.Init(new ItemCellModel(itemInfo[0], false, itemInfo[1]));
                itemBaisc.button.AddListener(() =>
                {
                    ItemTipUtility.Show(itemInfo[0]);
                });
            }
            else
            {
                itemBaisc.SetActive(false);
            }
        }
    }
}
Main/System/FestivalActivity/FestivalActivityGiftCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cce6bd2f32961ec42b60c48e47665255
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/FestivalActivityGiftWin.cs
New file
@@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using UnityEngine;
public class FestivalActivityGiftWin : UIBase
{
    [SerializeField] ButtonEx closeButton;
    [SerializeField] ScrollerController scroller;
    [SerializeField] TextEx timeText;
    FestivalActivityManager manager => FestivalActivityManager.Instance;
    StoreModel storeModel => StoreModel.Instance;
    protected override void InitComponent()
    {
        closeButton.SetListener(CloseWindow);
    }
    protected override void OnPreOpen()
    {
        scroller.OnRefreshCell += OnRefreshCell;
        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
        RechargeManager.Instance.rechargeCountEvent += OnRechargeCountEvent;
        storeModel.RefreshBuyShopLimitEvent += RefreshBuyShopLimitEvent;
        AdsManager.Instance.OnAdsInfoListUpdateEvent += OnAdsInfoListUpdateEvent;
        CreateGiftScroller();
        OnSecondEvent();
    }
    protected override void OnPreClose()
    {
        scroller.OnRefreshCell -= OnRefreshCell;
        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
        RechargeManager.Instance.rechargeCountEvent -= OnRechargeCountEvent;
        storeModel.RefreshBuyShopLimitEvent -= RefreshBuyShopLimitEvent;
        AdsManager.Instance.OnAdsInfoListUpdateEvent -= OnAdsInfoListUpdateEvent;
    }
    private void OnAdsInfoListUpdateEvent(int arg1, int arg2, int arg3)
    {
        RefreshAll();
    }
    private void OnRefreshCell(ScrollerDataType type, CellView cell)
    {
        var _cell = cell.GetComponent<FestivalActivityGiftCell>();
        _cell?.Display(cell.index, giftItems);
    }
    private void OnSecondEvent()
    {
        manager.GetActTimeStr(timeText);
    }
    private void OnRechargeCountEvent(int obj)
    {
        RefreshAll();
    }
    private void RefreshBuyShopLimitEvent()
    {
        RefreshAll();
    }
    List<FestivalActivityGiftItem> giftItems;
    private void CreateGiftScroller()
    {
        giftItems = manager.GetGiftItemList(true);
        scroller.Refresh();
        if (!giftItems.IsNullOrEmpty())
        {
            for (int i = 0; i < giftItems.Count; i++)
            {
                scroller.AddCell(ScrollerDataType.Header, i);
            }
        }
        scroller.Restart();
    }
    void RefreshAll()
    {
        scroller.m_Scorller.RefreshActiveCellViews();
    }
}
Main/System/FestivalActivity/FestivalActivityGiftWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 030c0370cba35da49bde2e5b27d0c437
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/FestivalActivityManager.cs
New file
@@ -0,0 +1,451 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class FestivalActivityManager : GameSystemManager<FestivalActivityManager>, IOpenServerActivity
{
    public override void Init()
    {
        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEventOnRelogin += OnBeforePlayerDataInitializeEventOnRelogin;
        DTC0403_tagPlayerLoginLoadOK.playerLoginOkEvent += OnPlayerLoginOk;
        FuncOpen.Instance.OnFuncStateChangeEvent += OnFuncStateChangeEvent;
        OperationTimeHepler.Instance.operationTimeUpdateEvent += OperationTimeUpdateEvent;
        OperationTimeHepler.Instance.operationStartEvent += OperationStartEvent;
        OperationTimeHepler.Instance.operationEndEvent += OperationEndEvent;
        OperationTimeHepler.Instance.operationAdvanceEvent += OperationAdvanceEvent;
        StoreModel.Instance.RefreshBuyShopLimitEvent += RefreshBuyShopLimitEvent;
        GeneralActInfoManager.Instance.OnUpdateActSignInfosEvent += OnUpdateActSignInfosEvent;
        HeroManager.Instance.onHeroChangeEvent += OnHeroChangeEvent;
        TimeMgr.Instance.OnDayEvent += OnDayEvent;
        AdsManager.Instance.OnAdsInfoListUpdateEvent += OnAdsInfoListUpdateEvent;
        InitRedPointId();
    }
    public override void Release()
    {
        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEventOnRelogin -= OnBeforePlayerDataInitializeEventOnRelogin;
        DTC0403_tagPlayerLoginLoadOK.playerLoginOkEvent -= OnPlayerLoginOk;
        FuncOpen.Instance.OnFuncStateChangeEvent -= OnFuncStateChangeEvent;
        OperationTimeHepler.Instance.operationTimeUpdateEvent -= OperationTimeUpdateEvent;
        OperationTimeHepler.Instance.operationStartEvent -= OperationStartEvent;
        OperationTimeHepler.Instance.operationEndEvent -= OperationEndEvent;
        OperationTimeHepler.Instance.operationAdvanceEvent -= OperationAdvanceEvent;
        StoreModel.Instance.RefreshBuyShopLimitEvent -= RefreshBuyShopLimitEvent;
        GeneralActInfoManager.Instance.OnUpdateActSignInfosEvent -= OnUpdateActSignInfosEvent;
        HeroManager.Instance.onHeroChangeEvent -= OnHeroChangeEvent;
        TimeMgr.Instance.OnDayEvent -= OnDayEvent;
        AdsManager.Instance.OnAdsInfoListUpdateEvent -= OnAdsInfoListUpdateEvent;
    }
    private void OnAdsInfoListUpdateEvent(int arg1, int arg2, int arg3)
    {
        UpdateRedpoint();
    }
    private void OnDayEvent()
    {
        UpdateRedpoint();
    }
    private void OnHeroChangeEvent(HeroInfo info)
    {
        UpdateRedpoint();
    }
    private void OnUpdateActSignInfosEvent(int arg1, int arg2)
    {
        UpdateRedpoint();
    }
    private void RefreshBuyShopLimitEvent()
    {
        UpdateRedpoint();
    }
    private void OnBeforePlayerDataInitializeEventOnRelogin()
    {
    }
    private void OnPlayerLoginOk()
    {
        TryPopWin();
    }
    private void OnFuncStateChangeEvent(int obj)
    {
        if (obj != (int)FuncOpenEnum.HeroDebut)
            return;
        TryPopWin();
    }
    public const int activityType = (int)OpenServerActivityCenter.ActivityType.AT_DateActivity;
    public const int activityID = (int)NewDayActivityID.FestivalActivityAct;
    public static OperationType operaType = OperationType.FestivalActivity;
    public Redpoint redPoint = new Redpoint(MainRedDot.FestivalActivityRepoint);
    public bool IsOpen => OperationTimeHepler.Instance.SatisfyOpenCondition(operaType);
    public bool IsAdvance => OperationTimeHepler.Instance.SatisfyAdvanceCondition(operaType);
    public bool priorityOpen => redPoint.state == RedPointState.Simple;
    public readonly int actNum = 30;
    public event Action<int> onStateUpdate;
    private void OperationTimeUpdateEvent(OperationType type)
    {
        if (type == operaType)
        {
            if (UIManager.Instance.IsOpened<FestivalActivityPopWin>())
                UIManager.Instance.CloseWindow<FestivalActivityPopWin>();
            if (UIManager.Instance.IsOpened<FestivalActivityWin>())
                UIManager.Instance.CloseWindow<FestivalActivityWin>();
            UpdateRedpoint();
        }
    }
    private void OperationStartEvent(OperationType type, int state)
    {
        if (type == operaType && state == 0)
        {
            onStateUpdate?.Invoke(activityID);
            TryPopWin();
            UpdateRedpoint();
        }
    }
    private void OperationEndEvent(OperationType type, int state)
    {
        if (type == operaType)
        {
            onStateUpdate?.Invoke(activityID);
            if (UIManager.Instance.IsOpened<FestivalActivityPopWin>())
                UIManager.Instance.CloseWindow<FestivalActivityPopWin>();
            if (UIManager.Instance.IsOpened<FestivalActivityWin>())
                UIManager.Instance.CloseWindow<FestivalActivityWin>();
            UpdateRedpoint();
        }
    }
    private void OperationAdvanceEvent(OperationType type)
    {
        if (type == operaType)
        {
            onStateUpdate?.Invoke(activityID);
            UpdateRedpoint();
        }
    }
    public OperationFlashSaleActivityInfo GetActInfo()
    {
        OperationTimeHepler.Instance.TryGetOperation(operaType, out OperationFlashSaleActivityInfo act);
        return act;
    }
    #region 红点
    public int GetRedPointId(FestivalActivityRepointType type)
    {
        return MainRedDot.FestivalActivityRepoint * 10 + (int)type;
    }
    public Redpoint shopRedpoint;
    public Redpoint giftRedpoint;
    public Redpoint rechargeRedpoint;
    public void InitRedPointId()
    {
        giftRedpoint ??= new Redpoint(MainRedDot.FestivalActivityRepoint, GetRedPointId(FestivalActivityRepointType.Gift));
        rechargeRedpoint ??= new Redpoint(MainRedDot.FestivalActivityRepoint, GetRedPointId(FestivalActivityRepointType.Recharge));
    }
    public void UpdateRedpoint()
    {
        redPoint.state = RedPointState.None;
        giftRedpoint.state = RedPointState.None;
        if (HasGiftCanHave())//礼包
            giftRedpoint.state = RedPointState.Simple;
    }
    #endregion
    #region 拍脸界面
    public bool IsTodayPop
    {
        get
        {
            int lastPopTime = LoadPopTimeData();
            int todayStartTime = TimeUtility.GetTodayStartTick();
            return lastPopTime < todayStartTime;
        }
    }
    private string PopTimeDataKey { get { return $"FestivalActivityManager_PopTimeData_{PlayerDatas.Instance.PlayerId}"; } }
    private int LoadPopTimeData()
    {
        return LocalSave.GetInt(PopTimeDataKey);
    }
    public void SavePopTimeData()
    {
        LocalSave.SetInt(PopTimeDataKey, TimeUtility.AllSeconds);
    }
    public void ClearPopTimeData()
    {
        LocalSave.SetInt(PopTimeDataKey, 0);
    }
    private void TryPopWin()
    {
        if (!IsFestivalActivityOpen()) return;
        if (!IsTodayPop) return;
        if (UIManager.Instance.IsOpened<FestivalActivityPopWin>()) return;
        if (UIManager.Instance.IsOpened<FestivalActivityWin>()) return;
        PopupWindowsProcessor.Instance.Add("FestivalActivityPopWin");
    }
    #endregion
    public void GetActTimeStr(TextEx timeText, string key = "TimeRush05")
    {
        var act = GetActInfo();
        if (act == null)
        {
            timeText.text = Language.Get("OSActivity6");
            return;
        }
        timeText.text = Language.Get(key, TimeUtility.SecondsToShortDHMS(act.GetResetSurplusTime()));
    }
    public Color32 ParseColor32(int[] colorArr)
    {
        return new Color32()
        {
            r = (byte)(colorArr.Length > 0 ? colorArr[0] : 0),
            g = (byte)(colorArr.Length > 1 ? colorArr[1] : 0),
            b = (byte)(colorArr.Length > 2 ? colorArr[2] : 0),
            a = (byte)(colorArr.Length > 3 ? colorArr[3] : 255),
        };
    }
    public bool IsFestivalActivityOpen()
    {
        if (!IsOpen) return false;
        if (!FuncOpen.Instance.IsFuncOpen((int)FuncOpenEnum.FestivalActivity)) return false;
        return true;
    }
    #region 限时礼包
    public bool IsCanBuy(int ctgID, out bool isNoLimitBuy, out int nowBuyCnt, out int maxBuyCnt)
    {
        isNoLimitBuy = false;
        nowBuyCnt = 0;
        maxBuyCnt = 0;
        CTGConfig config = CTGConfig.Get(ctgID);
        if (config == null)
            return false;
        if (!RechargeManager.Instance.TryGetRechargeCount(ctgID, out var rechargeCount))
            return false;
        // 所有限制都为0时,无限购买
        if (config.TotalBuyCount == 0 && config.DailyBuyCount == 0 &&
            config.WeekBuyCount == 0 && config.MonthBuyCount == 0)
        {
            isNoLimitBuy = true;
            return true;
        }
        // 按优先级检查:每日 > 每周 > 每月 > 总计
        if (config.DailyBuyCount > 0)
        {
            nowBuyCnt = rechargeCount.todayCount;
            maxBuyCnt = config.DailyBuyCount;
            return rechargeCount.todayCount < config.DailyBuyCount;
        }
        if (config.WeekBuyCount > 0)
        {
            nowBuyCnt = rechargeCount.weekPayCount;
            maxBuyCnt = config.WeekBuyCount;
            return rechargeCount.weekPayCount < config.WeekBuyCount;
        }
        if (config.MonthBuyCount > 0)
        {
            nowBuyCnt = rechargeCount.monthPayCount;
            maxBuyCnt = config.MonthBuyCount;
            return rechargeCount.monthPayCount < config.MonthBuyCount;
        }
        if (config.TotalBuyCount > 0)
        {
            nowBuyCnt = rechargeCount.totalCount;
            maxBuyCnt = config.TotalBuyCount;
            return rechargeCount.totalCount < config.TotalBuyCount;
        }
        return false;
    }
    // 免费商品
    public bool IsFreeShop(int shopID)
    {
        StoreConfig config = StoreConfig.Get(shopID);
        if (config == null) return false;
        return config.MoneyNum == 0;
    }
    //没售罄
    public bool IsNoSellOutShopID(int shopID)
    {
        StoreConfig config = StoreConfig.Get(shopID);
        if (config == null) return false;
        StoreModel.Instance.TryGetIsSellOut(config, out int remainNum);
        return remainNum > 0;
    }
    public List<FestivalActivityGiftItem> GetGiftItemList(bool isSort = false)
    {
        var act = GetActInfo();
        if (act == null) return null;
        var config = ActSpecialSaleConfig.Get(act.CfgID);
        if (config == null) return null;
        List<FestivalActivityGiftItem> res = new List<FestivalActivityGiftItem>();
        var list = StoreModel.Instance.storeTypeDict[config.ActShopType];
        if (!list.IsNullOrEmpty())
        {
            for (int i = 0; i < list.Count; i++)
            {
                var item = list[i];
                if (item.storeConfig == null)
                    continue;
                res.Add(new FestivalActivityGiftItem
                {
                    type = 0,
                    id = item.storeConfig.ID,
                });
            }
        }
        var adAwardConfig = ADAwardConfig.Get(config.ADID);
        if (adAwardConfig != null)
        {
            res.Add(new FestivalActivityGiftItem
            {
                type = 1,
                id = config.ADID,
            });
        }
        if (config.CTGIDList != null)
        {
            for (int i = 0; i < config.CTGIDList.Length; i++)
            {
                var item = config.CTGIDList[i];
                res.Add(new FestivalActivityGiftItem
                {
                    type = 2,
                    id = item,
                });
            }
        }
        if (isSort)
        {
            res = res.OrderBy(item =>
            {
                bool isCanBuy;
                if (item.type == 0) // 商店
                {
                    isCanBuy = IsNoSellOutShopID(item.id);
                }
                else if (item.type == 1) // 广告
                {
                    isCanBuy = IsAdAwardCanReceive(item.id);
                }
                else // 充值
                {
                    isCanBuy = IsCanBuy(item.id, out bool isNoLimitBuy, out int nowBuyCnt, out int maxBuyCnt);
                }
                return !isCanBuy;
            })
            .ThenBy(item => GetSortOrder(item))
            .ThenBy(item => item.id)
            .ToList();
        }
        return res;
    }
    // 广告是否已领取完
    public bool IsAdAwardCanReceive(int adID)
    {
        var config = ADAwardConfig.Get(adID);
        if (config == null) return false;
        int receivedCnt = AdsManager.Instance.GetADCntByADID(adID);
        return receivedCnt < config.ADCntMax;
    }
    private int GetSortOrder(FestivalActivityGiftItem item)
    {
        if (item.type == 0) // 商店
        {
            return IsFreeShop(item.id) ? 0 : 2; // 免费=0, 元宝=2
        }
        if (item.type == 1) // 广告
        {
            return 1;
        }
        return 3; // RMB (type == 2)
    }
    public bool HasGiftCanHave()
    {
        var list = GetGiftItemList(false);
        if (list.IsNullOrEmpty())
            return false;
        for (int i = 0; i < list.Count; i++)
        {
            var item = list[i];
            if (item.type == 0)
            {
                bool isFree = IsFreeShop(item.id);
                bool isCanBuy = IsNoSellOutShopID(item.id);
                if (isFree && isCanBuy)
                    return true;
            }
        }
        var act = GetActInfo();
        if (act == null) return false;
        var config = ActSpecialSaleConfig.Get(act.CfgID);
        if (config == null) return false;
        var adAwardConfig = ADAwardConfig.Get(config.ADID);
        if (adAwardConfig == null) return false;
        if (IsAdAwardCanReceive(config.ADID))
            return true;
        return false;
    }
    #endregion
}
public enum FestivalActivityRepointType
{
    CheckIn = 1,
    Mission = 2,
    Shop = 3,
    Gift = 4,
    Recharge = 5,
    TotalRecharge = 6,
    TotDayRecharge = 7,
}
public class FestivalActivityGiftItem
{
    public int type;//0 商店id 1 广告id 2 充值id
    public int id;
}
Main/System/FestivalActivity/FestivalActivityManager.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e28bb6a585249d94eabdd1bf556d81e7
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/FestivalActivityMissionCell.cs
New file
@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
public class FestivalActivityMissionCell : CellView
{
    [SerializeField] Text nameText;
    [SerializeField] Image processImg;
    [SerializeField] Text processText;
    [SerializeField] ItemCell[] itemCells;
    [SerializeField] Button getBtn;
    [SerializeField] Button gotoBtn;
    [SerializeField] Transform gotRect;
    public void Display(ActTaskTempConfig config, int taskIndex)
    {
        int targetValue = config.NeedValue;
        uint curValue = FestivalActivityMissionManager.Instance.GetTaskProgress((byte)config.TaskType);
        // 使用新的语言键格式 ActTaskType{TaskType}
        nameText.text = Language.Get($"ActTaskType{config.TaskType}", config.NeedValue);
        processImg.fillAmount = Mathf.Clamp01((float)curValue / targetValue);
        processText.text = Mathf.Min(targetValue, (int)curValue) + "/" + targetValue;
        var state = FestivalActivityMissionManager.Instance.GetTaskState(config.TasklD);
        for (int i = 0; i < itemCells.Length; i++)
        {
            if (i < config.AwardItemList.Length)
            {
                itemCells[i].SetActive(true);
                int itemID = config.AwardItemList[i][0];
                itemCells[i].Init(new ItemCellModel(itemID, false, config.AwardItemList[i][1]));
                itemCells[i].button.AddListener(() =>
                {
                    ItemTipUtility.Show(itemID);
                });
            }
            else
            {
                itemCells[i].SetActive(false);
            }
        }
        getBtn.SetActive(state == 1);
        gotRect.SetActive(state == 2);
        gotoBtn.SetActive(state == 0);
        getBtn.AddListener(() =>
        {
            FestivalActivityMissionManager.Instance.SendGetAward(config.TasklD);
        });
        gotoBtn.AddListener(() =>
        {
            UIManager.Instance.CloseWindow<FestivalActivityWin>();
            if (config.GuideID > 0)
            {
                NewBieCenter.Instance.StartNewBieGuide(config.GuideID);
            }
        });
    }
}
Main/System/FestivalActivity/FestivalActivityMissionCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f1170cec164834e4ab20b21cb2be5cca
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/FestivalActivityMissionManager.cs
New file
@@ -0,0 +1,471 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class FestivalActivityMissionManager : GameSystemManager<FestivalActivityMissionManager>, IOpenServerActivity
{
    public readonly int ActNum = 30;
    // 玩家任务进度信息 (差异更新字典: 任务类型 -> 当前任务值)
    private Dictionary<int, uint> taskProgressDict = new Dictionary<int, uint>();
    public uint ActScoreTotal;    // 累计活动积分,用于验证领取累计积分奖励用,商店兑换直接用物品兑换物品
    public uint ActScoreAward;    // 累计活动积分领奖记录,按奖励索引位运算判断是否已领取
    public byte AwardCount;
    public uint[] AwardRecordList;    // 任务ID领奖记录值列表,根据任务ID位判断是否已领取,一个记录值存31位 [记录值0, 记录值1, ...]
    public override void Init()
    {
        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEventOnRelogin += OnBeforePlayerDataInitializeEventOnRelogin;
        OperationTimeHepler.Instance.operationTimeUpdateEvent += OperationTimeUpdateEvent;
        OperationTimeHepler.Instance.operationStartEvent += OperationStartEvent;
        OperationTimeHepler.Instance.operationEndEvent += OperationEndEvent;
        OperationTimeHepler.Instance.operationAdvanceEvent += OperationAdvanceEvent;
        FuncOpen.Instance.OnFuncStateChangeEvent += OnFuncStateChangeEvent;
        StoreModel.Instance.RefreshBuyShopLimitEvent += OnRefreshBuyShopLimitEvent;
        TimeMgr.Instance.OnDayEvent += OnDayEvent;
        InitShopRedPointId();
    }
    public override void Release()
    {
        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEventOnRelogin -= OnBeforePlayerDataInitializeEventOnRelogin;
        OperationTimeHepler.Instance.operationTimeUpdateEvent -= OperationTimeUpdateEvent;
        OperationTimeHepler.Instance.operationStartEvent -= OperationStartEvent;
        OperationTimeHepler.Instance.operationEndEvent -= OperationEndEvent;
        OperationTimeHepler.Instance.operationAdvanceEvent -= OperationAdvanceEvent;
        FuncOpen.Instance.OnFuncStateChangeEvent -= OnFuncStateChangeEvent;
        StoreModel.Instance.RefreshBuyShopLimitEvent -= OnRefreshBuyShopLimitEvent;
        TimeMgr.Instance.OnDayEvent -= OnDayEvent;
    }
    private void OnDayEvent()
    {
        UpdateRedPoint();
    }
    private void OnRefreshBuyShopLimitEvent()
    {
        UpdateRedPoint();
    }
    private void OnFuncStateChangeEvent(int obj)
    {
        if (obj != (int)FuncOpenEnum.FestivalActivity)
            return;
        UpdateRedPoint();
    }
    private void OnBeforePlayerDataInitializeEventOnRelogin()
    {
        taskProgressDict.Clear();
        ActScoreTotal = 0;
        ActScoreAward = 0;
        AwardCount = 0;
        AwardRecordList = null;
        UpdateRedPoint();
    }
    public const int activityType = (int)OpenServerActivityCenter.ActivityType.AT_DateActivity;
    public const int activityID = (int)NewDayActivityID.FestivalActivityMissionAct;
    public static OperationType operaType = OperationType.FestivalActivity_Mission;
    public Redpoint redPoint = new Redpoint(MainRedDot.FestivalActivityRepoint, FestivalActivityManager.Instance.GetRedPointId(FestivalActivityRepointType.Mission));
    // 实时获取当前活动配置
    public ActTaskConfig GetCurrentConfig()
    {
        if (!OperationTimeHepler.Instance.TryGetOperation(operaType, out OperationMissionActivityInfo operation))
            return null;
        return ActTaskConfig.Get(operation.CfgID);
    }
    // 实时获取任务模板列表
    private List<ActTaskTempConfig> GetCurrentTaskList()
    {
        ActTaskConfig config = GetCurrentConfig();
        if (config == null)
            return null;
        return ActTaskTempConfig.GetTemplateIDToConfigsDict(config.TemplateID);
    }
    public bool IsOpen => OperationTimeHepler.Instance.SatisfyOpenCondition(operaType);
    public bool IsAdvance => OperationTimeHepler.Instance.SatisfyAdvanceCondition(operaType);
    public bool priorityOpen => redPoint.state == RedPointState.Simple;
    public event Action<int> onStateUpdate;
    public event Action OnMissionDataChangeEvent;
    private void OperationTimeUpdateEvent(OperationType type)
    {
        if (type != operaType)
            return;
        if (UIManager.Instance.IsOpened<FestivalActivityMissionWin>())
            UIManager.Instance.CloseWindow<FestivalActivityMissionWin>();
        // 实时获取活动配置
        if (!OperationTimeHepler.Instance.TryGetOperation(operaType, out OperationMissionActivityInfo operation))
            return;
        ActTaskConfig config = ActTaskConfig.Get(operation.CfgID);
        if (config == null)
            return;
        UpdateRedPoint();
    }
    private void OperationStartEvent(OperationType type, int state)
    {
        if (type == operaType && state == 0)
        {
            // 实时获取活动配置
            if (!OperationTimeHepler.Instance.TryGetOperation(operaType, out OperationMissionActivityInfo operation))
                return;
            ActTaskConfig config = ActTaskConfig.Get(operation.CfgID);
            if (config == null)
                return;
            UpdateRedPoint();
            onStateUpdate?.Invoke(activityID);
        }
    }
    private void OperationEndEvent(OperationType type, int state)
    {
        if (type == operaType)
        {
            if (UIManager.Instance.IsOpened<FestivalActivityMissionWin>())
                UIManager.Instance.CloseWindow<FestivalActivityMissionWin>();
            UpdateRedPoint();
            onStateUpdate?.Invoke(activityID);
        }
    }
    private void OperationAdvanceEvent(OperationType type)
    {
        if (type == operaType)
        {
            // 实时获取活动配置
            if (!OperationTimeHepler.Instance.TryGetOperation(operaType, out OperationMissionActivityInfo operation))
                return;
            ActTaskConfig config = ActTaskConfig.Get(operation.CfgID);
            if (config == null)
                return;
            UpdateRedPoint();
            onStateUpdate?.Invoke(activityID);
        }
    }
    public void UpdateRedPoint()
    {
        redPoint.state = RedPointState.None;
        if (shopRedpoint != null)
            shopRedpoint.state = RedPointState.None;
        if (!FuncOpen.Instance.IsFuncOpen((int)FuncOpenEnum.FestivalActivity))
            return;
        if (!IsOpen)
            return;
        ActTaskConfig config = GetCurrentConfig();
        if (config == null)
            return;
        var taskList = GetCurrentTaskList();
        if (taskList == null)
            return;
        // 检查任务是否有可领取的
        for (int i = 0; i < taskList.Count; i++)
        {
            if (GetTaskState(taskList[i].TasklD) == 1)
            {
                redPoint.state = RedPointState.Simple;
                break;
            }
        }
        // 检查累计积分奖励是否有可领取的
        var totalScoreAwardList = ActTaskTempConfig.GetTotalScoreAwardListByCfgID(config.CfgID);
        for (int i = 0; i < totalScoreAwardList.Count; i++)
        {
            if (GetTotalScoreState(i) == 1)
            {
                redPoint.state = RedPointState.Simple;
                break;
            }
        }
        // 兑换商店红点
        if (shopRedpoint != null && ShowShopRedpoint())
            shopRedpoint.state = RedPointState.Simple;
    }
    // 获取任务列表(排序:1可领取 > 0不可领取 > 2已领取)
    public List<ActTaskTempConfig> GetTaskConfigList()
    {
        var taskList = GetCurrentTaskList();
        if (taskList == null)
            return new List<ActTaskTempConfig>();
        // 按任务状态排序:1可领取 > 0不可领取 > 2已领取
        return taskList.OrderBy(t => GetTaskState(t.TasklD) == 2)
            .ThenBy(t => GetTaskState(t.TasklD) == 0)
            .ToList();
    }
    // 获取任务状态: 0不可领取 1可领取 2已领取
    public int GetTaskState(int taskId)
    {
        if (AwardRecordList == null)
            return 0;
        var taskList = GetCurrentTaskList();
        if (taskList == null)
            return 0;
        // 检查是否已领取
        if (IsTaskAwardReceived(taskId))
            return 2;
        // 检查是否达成
        if (CanReceiveTaskAward(taskId))
            return 1;
        return 0;
    }
    // 检查任务奖励是否已领取
    private bool IsTaskAwardReceived(int id)
    {
        if (AwardRecordList == null)
            return false;
        var index = id / 31;
        var bit = id % 31;
        return (AwardRecordList[index] & (1u << bit)) != 0;
    }
    // 检查任务是否可领取
    private bool CanReceiveTaskAward(int taskId)
    {
        if (taskProgressDict.Count == 0)
            return false;
        var taskList = GetCurrentTaskList();
        if (taskList == null)
            return false;
        var config = taskList.FirstOrDefault(t => t.TasklD == taskId);
        if (config == null)
            return false;
        uint currentValue = GetTaskProgress((byte)config.TaskType);
        return currentValue >= (uint)config.NeedValue;
    }
    // 获取任务当前进度
    public uint GetTaskProgress(byte taskType)
    {
        if (taskProgressDict.TryGetValue(taskType, out uint value))
            return value;
        return 0;
    }
    // 获取任务目标值
    public uint GetTaskTarget(byte taskType)
    {
        var taskList = GetCurrentTaskList();
        if (taskList == null)
            return 0;
        var config = taskList.FirstOrDefault(t => t.TaskType == taskType);
        if (config == null)
            return 0;
        return (uint)config.NeedValue;
    }
    // 获取累计积分奖励状态: 0不可领取 1可领取 2已领取
    public int GetTotalScoreState(int awardIndex)
    {
        if (AwardRecordList == null)
            return 0;
        ActTaskConfig config = GetCurrentConfig();
        if (config == null)
            return 0;
        var totalScoreAwardList = ActTaskTempConfig.GetTotalScoreAwardListByCfgID(config.CfgID);
        if (awardIndex < 0 || awardIndex >= totalScoreAwardList.Count)
            return 0;
        // 检查是否已领取
        if (IsTotalScoreAwardReceived(awardIndex))
            return 2;
        // 检查积分是否足够
        if (ActScoreTotal >= (uint)totalScoreAwardList[awardIndex].needScore)
            return 1;
        return 0;
    }
    // 检查累计积分奖励是否已领取
    private bool IsTotalScoreAwardReceived(int awardIndex)
    {
        if (AwardRecordList == null)
            return false;
        return (ActScoreAward & (1u << awardIndex)) != 0;
    }
    // 获取累计积分
    public uint GetTotalScore()
    {
        return ActScoreTotal;
    }
    // 获取累计积分奖励列表
    public List<ActTaskTempConfig.TotalScoreAwardConfig> GetTotalScoreAwardList()
    {
        ActTaskConfig config = GetCurrentConfig();
        if (config == null)
            return new List<ActTaskTempConfig.TotalScoreAwardConfig>();
        return ActTaskTempConfig.GetTotalScoreAwardListByCfgID(config.CfgID);
    }
    // 处理玩家任务进度信息 (HAA72)
    public void UpdatePlayerValueInfo(HAA72_tagSCActTaskPlayerValueInfo info)
    {
        if (ActNum != info.ActNum)
            return;
        for (int i = 0; i < info.TaskValueList.Length; i++)
        {
            var taskValue = info.TaskValueList[i];
            taskProgressDict[(int)taskValue.TaskType] = taskValue.TaskValue;
        }
        UpdateRedPoint();
        OnMissionDataChangeEvent?.Invoke();
    }
    // 处理玩家奖励领取信息 (HAA73)
    public void UpdatePlayerInfo(HAA73_tagSCActTaskPlayerInfo info)
    {
        if (ActNum != info.ActNum)
            return;
        ActScoreTotal = info.ActScoreTotal;
        ActScoreAward = info.ActScoreAward;
        AwardCount = info.AwardCount;
        AwardRecordList = info.AwardRecordList;
        UpdateRedPoint();
        OnMissionDataChangeEvent?.Invoke();
    }
    // 发送领取任务奖励
    public void SendGetAward(int taskId)
    {
        string actStr = ActNum.ToString();
        var pack = new CA504_tagCMPlayerGetReward();
        pack.RewardType = 71;
        pack.DataEx = (uint)taskId;
        pack.DataExStr = actStr;
        pack.DataExStrLen = (byte)actStr.Length;
        GameNetSystem.Instance.SendInfo(pack);
    }
    // 发送领取累计积分奖励
    public void SendGetTotalScoreAward()
    {
        string actStr = ActNum.ToString();
        var pack = new CA504_tagCMPlayerGetReward();
        pack.RewardType = 71;
        pack.DataEx = 0; // 0表示领取累计积分奖励
        pack.DataExStr = actStr;
        pack.DataExStrLen = (byte)actStr.Length;
        GameNetSystem.Instance.SendInfo(pack);
    }
    public string GetActTimeStr()
    {
        if (!OperationTimeHepler.Instance.TryGetOperation(operaType, out OperationMissionActivityInfo operation))
        {
            return Language.Get("OSActivity6");
        }
        return Language.Get("TotalRecharge08", TimeUtility.SecondsToShortDHMS(operation.GetResetSurplusTime()));
    }
    public void GetActTimeStr(TextEx timeText, string key = "TimeRush05")
    {
        timeText.text = GetActTimeStr();
    }
    #region 兑换商店
    private string ShopVisitTimeDataKey { get { return $"FestivalActivityMissionManager_ShopVisitTime_{PlayerDatas.Instance.PlayerId}"; } }
    private int LoadShopVisitTimeData()
    {
        return LocalSave.GetInt(ShopVisitTimeDataKey);
    }
    public void SaveShopVisitTimeData()
    {
        LocalSave.SetInt(ShopVisitTimeDataKey, TimeUtility.AllSeconds);
    }
    public bool IsShopVisitedToday
    {
        get
        {
            int lastVisitTime = LoadShopVisitTimeData();
            int todayStartTime = TimeUtility.GetTodayStartTick();
            return lastVisitTime >= todayStartTime;
        }
    }
    public Redpoint shopRedpoint;
    public void InitShopRedPointId()
    {
        shopRedpoint ??= new Redpoint(MainRedDot.FestivalActivityRepoint, FestivalActivityManager.Instance.GetRedPointId(FestivalActivityRepointType.Shop));
    }
    public bool ShowShopRedpoint()
    {
        ActTaskConfig config = GetCurrentConfig();
        if (config == null)
            return false;
        if (!StoreModel.Instance.storeTypeDict.TryGetValue(config.ActShopTypeEx, out var list) || list.IsNullOrEmpty())
            return false;
        for (int i = 0; i < list.Count; i++)
        {
            var item = list[i];
            bool isFree = IsFreeShop(item.shopId);
            bool isCanBuy = IsNoSellOutShopID(item.shopId);
            if (isFree && isCanBuy)
                return true;
        }
        return !IsShopVisitedToday;
    }
    public bool IsFreeShop(int shopID)
    {
        StoreConfig config = StoreConfig.Get(shopID);
        if (config == null) return false;
        return config.MoneyNum == 0;
    }
    public bool IsNoSellOutShopID(int shopID)
    {
        StoreConfig config = StoreConfig.Get(shopID);
        if (config == null) return false;
        StoreModel.Instance.TryGetIsSellOut(config, out int remainNum);
        return remainNum > 0;
    }
    #endregion
}
Main/System/FestivalActivity/FestivalActivityMissionManager.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 16ba7e2787f697440a4d3ad20ecec557
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/FestivalActivityMissionWin.cs
New file
@@ -0,0 +1,157 @@
//--------------------------------------------------------
//    [Author]:           玩个游戏
//    [  Date ]:           Tuesday, July 24, 2018
//--------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
////开服盛典
public class FestivalActivityMissionWin : UIBase
{
    [SerializeField] ButtonEx closeButton;
    [SerializeField] Image processImg;
    [SerializeField] Image iconImg;
    [SerializeField] Text galaTimeText;
    [SerializeField] Text totalScoreText;
    [SerializeField] ItemCell[] itemCells;
    [SerializeField] Image[] gotImgs;
    [SerializeField] Text[] scoreTexts;
    [SerializeField] UIEffectPlayer[] effectPlayers;
    [SerializeField] ScrollerController scroller;
    List<ActTaskTempConfig> taskConfigs = new List<ActTaskTempConfig>();
    protected override void InitComponent()
    {
        closeButton.SetListener(CloseWindow);
    }
    protected override void OnPreOpen()
    {
        FestivalActivityMissionManager.Instance.OnMissionDataChangeEvent += OnMissionDataChangeEvent;
        GlobalTimeEvent.Instance.secondEvent += ShowTime;
        StoreModel.Instance.RefreshBuyShopLimitEvent += OnRefreshBuyShopLimitEvent;
        scroller.OnRefreshCell += OnRefreshCell;
        RefreshScroller();
        Display();
        var config = FestivalActivityMissionManager.Instance.GetCurrentConfig();
        if (config != null)
        {
            iconImg.SetItemSprite(config.ActScoreItemID);
        }
    }
    protected override void OnPreClose()
    {
        FestivalActivityMissionManager.Instance.OnMissionDataChangeEvent -= OnMissionDataChangeEvent;
        GlobalTimeEvent.Instance.secondEvent -= ShowTime;
        StoreModel.Instance.RefreshBuyShopLimitEvent -= OnRefreshBuyShopLimitEvent;
        scroller.OnRefreshCell -= OnRefreshCell;
    }
    void OnMissionDataChangeEvent()
    {
        scroller.m_Scorller.RefreshActiveCellViews();
        Display();
    }
    void RefreshScroller()
    {
        taskConfigs = FestivalActivityMissionManager.Instance.GetTaskConfigList();
        var count = taskConfigs.Count;
        scroller.Refresh();
        for (int i = 0; i < count; i++)
        {
            scroller.AddCell(ScrollerDataType.Header, i);
        }
        scroller.Restart();
    }
    void OnRefreshCell(ScrollerDataType type, CellView cell)
    {
        var _cell = cell as FestivalActivityMissionCell;
        _cell.Display(taskConfigs[cell.index], cell.index);
    }
    private void OnRefreshBuyShopLimitEvent()
    {
        Display();
    }
    void Display()
    {
        uint totalScore = FestivalActivityMissionManager.Instance.GetTotalScore();
        var awardList = FestivalActivityMissionManager.Instance.GetTotalScoreAwardList();
        // 进度条计算
        uint maxScore = 0;
        if (awardList != null && awardList.Count > 0)
        {
            maxScore = (uint)awardList[awardList.Count - 1].needScore;
        }
        if (maxScore > 0)
        {
            processImg.fillAmount = Mathf.Clamp01((float)totalScore / maxScore);
        }
        else
        {
            processImg.fillAmount = 0;
        }
        ShowTime();
        totalScoreText.text = Language.Get("FestivalActivityMissionScore", totalScore);
        for (int i = 0; i < itemCells.Length; i++)
        {
            if (i < awardList.Count)
            {
                itemCells[i].SetActive(true);
                int index = i;
                int itemID = awardList[i].itemId;
                itemCells[i].Init(new ItemCellModel(itemID, false, awardList[i].itemCount));
                itemCells[i].button.AddListener(() =>
                {
                    if (FestivalActivityMissionManager.Instance.GetTotalScoreState(index) != 1)
                    {
                        ItemTipUtility.Show(itemID);
                        return;
                    }
                    FestivalActivityMissionManager.Instance.SendGetTotalScoreAward();
                });
                gotImgs[i].SetActive(FestivalActivityMissionManager.Instance.GetTotalScoreState(i) == 2);
                scoreTexts[i].text = awardList[i].needScore.ToString();
                if (FestivalActivityMissionManager.Instance.GetTotalScoreState(i) == 1)
                {
                    effectPlayers[i].Play();
                }
                else
                {
                    effectPlayers[i].Stop();
                }
            }
            else
            {
                itemCells[i].SetActive(false);
            }
        }
    }
    void ShowTime()
    {
        galaTimeText.text = FestivalActivityMissionManager.Instance.GetActTimeStr();
    }
}
Main/System/FestivalActivity/FestivalActivityMissionWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8cc4efe602e822743a4ee236fcd0e3d4
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/FestivalActivityPopCell.cs
New file
@@ -0,0 +1,19 @@
using UnityEngine;
public class FestivalActivityPopCell : CellView
{
    [SerializeField] ItemCell itemCell;
    public void Display(int index, int[][] popItems)
    {
        if (popItems == null || popItems.Length <= index || index < 0)
            return;
        int itemID = popItems[index][0];
        int itemCount = popItems[index][1];
        itemCell.Init(new ItemCellModel(itemID, false, itemCount));
        itemCell.countText.SetActive(itemCount > 1);
        itemCell.button.AddListener(() =>
        {
            ItemTipUtility.Show(itemID);
        });
    }
}
Main/System/FestivalActivity/FestivalActivityPopCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5698be6bce9f11240b0f8866851956f3
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/FestivalActivityPopWin.cs
New file
@@ -0,0 +1,83 @@
using UnityEngine;
using UnityEngine.UI;
public class FestivalActivityPopWin : UIBase
{
    [SerializeField] TextEx timeText;
    [SerializeField] ButtonEx goButton;
    [SerializeField] ButtonEx closeButton;
    [SerializeField] Toggle todayPopToggle;
    [SerializeField] ScrollerController scroller;
    FestivalActivityManager manager => FestivalActivityManager.Instance;
    protected override void InitComponent()
    {
        closeButton.SetListener(CloseWindow);
        goButton.SetListener(() =>
        {
            UIManager.Instance.CloseWindow<FestivalActivityPopWin>();
            if (!UIManager.Instance.IsOpened<FestivalActivityWin>())
                UIManager.Instance.OpenWindow<FestivalActivityWin>();
        });
        todayPopToggle.AddListener((bool value) =>
        {
            if (value)
            {
                // 勾选:今日不再弹出
                manager.SavePopTimeData();
            }
            else
            {
                // 取消勾选:今日依然可以弹出(重置时间记录)
                manager.ClearPopTimeData();
            }
        });
    }
    protected override void OnPreOpen()
    {
        scroller.OnRefreshCell += OnRefreshCell;
        todayPopToggle.isOn = !manager.IsTodayPop;
        DisplayTime();
        CreateScroller();
    }
    protected override void OnPreClose()
    {
        scroller.OnRefreshCell -= OnRefreshCell;
    }
    void OnRefreshCell(ScrollerDataType type, CellView cell)
    {
        var _cell = cell as FestivalActivityPopCell;
        _cell.Display(cell.index, popItems);
    }
    int[][] popItems;
    void CreateScroller()
    {
        var act = manager.GetActInfo();
        if (act == null)
            return;
        var config = ActSpecialSaleConfig.Get(act.CfgID);
        if (config == null)
            return;
        popItems = config.PopItems;
        scroller.Refresh();
        if (popItems != null)
        {
            for (int i = 0; i < popItems.Length; i++)
            {
                scroller.AddCell(ScrollerDataType.Header, i);
            }
        }
        scroller.Restart();
    }
    private void DisplayTime()
    {
        var act = manager.GetActInfo();
        timeText.text = act == null ? string.Empty : Language.Get("FestivalActivity01", act.ToDisplayTime());
    }
}
Main/System/FestivalActivity/FestivalActivityPopWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6a7825299693150499da31b4f94eefbb
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/FestivalActivityRechargeBaseWin.cs
New file
@@ -0,0 +1,52 @@
using System;
using UnityEngine;
public class FestivalActivityRechargeBaseWin : FunctionsBaseWin
{
    [SerializeField] TextEx timeText;
    [SerializeField] ButtonEx closeButton;
    FestivalActivityManager manager => FestivalActivityManager.Instance;
    protected override void InitComponent()
    {
        base.InitComponent();
        closeButton.SetListener(CloseWindow);
    }
    protected override void OnPreOpen()
    {
        base.OnPreOpen();
        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
        tabButtons[0].redpoint.redpointId = FestivalActivityManager.Instance.GetRedPointId(FestivalActivityRepointType.TotalRecharge);
        tabButtons[1].redpoint.redpointId = FestivalActivityManager.Instance.GetRedPointId(FestivalActivityRepointType.TotDayRecharge);
        OnSecondEvent();
    }
    protected override void OnPreClose()
    {
        base.OnPreClose();
        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
    }
    protected override void OpenSubUIByTabIndex()
    {
        switch (functionOrder)
        {
            case 0:
                currentSubUI = UIManager.Instance.OpenWindow<FestivalActivityRechargeTotalWin>();
                break;
            case 1:
                currentSubUI = UIManager.Instance.OpenWindow<FestivalActivityRechargeTotDayWin>();
                break;
        }
    }
    private void OnSecondEvent()
    {
        var act = manager.GetActInfo();
        if (act == null)
        {
            timeText.text = Language.Get("OSActivity6");
            return;
        }
        timeText.text = Language.Get("TotalRecharge08", TimeUtility.SecondsToShortDHMS(act.GetResetSurplusTime()));
    }
}
Main/System/FestivalActivity/FestivalActivityRechargeBaseWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2ed22b2a27c50074ab0addf5fe7c945e
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/FestivalActivityRechargeTotDayCell.cs
New file
@@ -0,0 +1,74 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class FestivalActivityRechargeTotDayCell : CellView
{
    [SerializeField] Text nameText;
    [SerializeField] Image processImage;
    [SerializeField] Text processText;
    [SerializeField] ItemCell[] itemCells;
    [SerializeField] Button getBtn;
    [SerializeField] Button gotoBtn;
    [SerializeField] Transform gotRect;
    FestivalActivityRechargeTotDayManager manager { get { return FestivalActivityRechargeTotDayManager.Instance; } }
    public void Display(int index, List<int> list)
    {
        if (list.IsNullOrEmpty() || index < 0 || index >= list.Count)
            return;
        int awardID = list[index];
        var config = ActTotDayRechargeTempConfig.Get(awardID);
        if (config == null)
            return;
        nameText.text = Language.Get($"TotalRecharge03", config.NeedDay);
        if (config.AwardItemList != null)
        {
            for (int i = 0; i < itemCells.Length; i++)
            {
                var cell = itemCells[i];
                if (i < config.AwardItemList.Length)
                {
                    var item = config.AwardItemList[i];
                    cell.SetActive(true);
                    cell.Init(new ItemCellModel(item[0], false, item[1]));
                    cell.button.AddListener(() => ItemTipUtility.Show(item[0]));
                }
                else
                {
                    cell.SetActive(false);
                }
            }
        }
        processText.text = Language.Get("BoneField09", manager.totalDays, config.NeedDay);
        processImage.fillAmount = manager.totalDays / (float)config.NeedDay;
        int state = manager.GetState(awardID);// 获取奖励状态 0 不可领取 1 未领取 2 已领取
        gotoBtn.SetActive(state == 0);
        getBtn.SetActive(state == 1);
        gotRect.SetActive(state == 2);
        getBtn.SetListener(() => manager.SendGetReward(config.NeedDay));
        gotoBtn.SetListener(() =>
        {
            if (FuncOpen.Instance.IsFuncOpen((int)FuncOpenEnum.Recharge, true))
            {
                RechargeManager.Instance.selectTabIndex = 1;
                if (UIManager.Instance.IsOpened<StoreBaseWin>())
                {
                    UIManager.Instance.GetUI<StoreBaseWin>().ClickFuncBtn(2);
                }
                else
                {
                    UIManager.Instance.OpenWindow<StoreBaseWin>(2);
                }
            }
        });
    }
}
Main/System/FestivalActivity/FestivalActivityRechargeTotDayCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a0ea141844e14b645b403981c1b265c0
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/FestivalActivityRechargeTotDayManager.cs
New file
@@ -0,0 +1,248 @@
using System;
using System.Collections.Generic;
using System.Linq;
public class FestivalActivityRechargeTotDayManager : GameSystemManager<FestivalActivityRechargeTotDayManager>, IOpenServerActivity
{
    public readonly int ActNum = 30;
    public override void Init()
    {
        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEventOnRelogin += OnBeforePlayerDataInitializeEventOnRelogin;
        OperationTimeHepler.Instance.operationTimeUpdateEvent += OperationTimeUpdateEvent;
        OperationTimeHepler.Instance.operationStartEvent += OperationStartEvent;
        OperationTimeHepler.Instance.operationEndEvent += OperationEndEvent;
        OperationTimeHepler.Instance.operationAdvanceEvent += OperationAdvanceEvent;
        FuncOpen.Instance.OnFuncStateChangeEvent += OnFuncStateChangeEvent;
        StoreModel.Instance.RefreshBuyShopLimitEvent += OnRefreshBuyShopLimitEvent;
    }
    public override void Release()
    {
        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEventOnRelogin -= OnBeforePlayerDataInitializeEventOnRelogin;
        OperationTimeHepler.Instance.operationTimeUpdateEvent -= OperationTimeUpdateEvent;
        OperationTimeHepler.Instance.operationStartEvent -= OperationStartEvent;
        OperationTimeHepler.Instance.operationEndEvent -= OperationEndEvent;
        OperationTimeHepler.Instance.operationAdvanceEvent -= OperationAdvanceEvent;
        FuncOpen.Instance.OnFuncStateChangeEvent -= OnFuncStateChangeEvent;
        StoreModel.Instance.RefreshBuyShopLimitEvent -= OnRefreshBuyShopLimitEvent;
    }
    private void OnRefreshBuyShopLimitEvent()
    {
        UpdateRedPoint();
    }
    private void OnFuncStateChangeEvent(int obj)
    {
        if (obj != (int)FuncOpenEnum.OSGala)
            return;
        UpdateRedPoint();
    }
    private void OnBeforePlayerDataInitializeEventOnRelogin()
    {
        totalDays = 0;
        awardRecord = 0;
    }
    public const int activityType = (int)OpenServerActivityCenter.ActivityType.AT_DateActivity;
    public const int activityID = (int)NewDayActivityID.FestivalActivityRechargeTotDayAct;
    public static OperationType operaType = OperationType.FestivalActivity_RechargeTotDay;
    // 总奖励
    public Redpoint redPoint = new Redpoint(
       FestivalActivityManager.Instance.GetRedPointId(FestivalActivityRepointType.Recharge),
       FestivalActivityManager.Instance.GetRedPointId(FestivalActivityRepointType.TotDayRecharge));
    public bool IsOpen => OperationTimeHepler.Instance.SatisfyOpenCondition(operaType);
    public bool IsAdvance => OperationTimeHepler.Instance.SatisfyAdvanceCondition(operaType);
    public bool priorityOpen => redPoint.state == RedPointState.Simple;
    public event Action<int> onStateUpdate;
    private void OperationTimeUpdateEvent(OperationType type)
    {
        if (UIManager.Instance.IsOpened<FestivalActivityRechargeBaseWin>())
            UIManager.Instance.CloseWindow<FestivalActivityRechargeBaseWin>();
        UpdateRedPoint();
    }
    private void OperationStartEvent(OperationType type, int state)
    {
        if (type == operaType && state == 0)
        {
            UpdateRedPoint();
            onStateUpdate?.Invoke(activityID);
        }
    }
    private void OperationEndEvent(OperationType type, int state)
    {
        if (type == operaType)
        {
            if (UIManager.Instance.IsOpened<FestivalActivityRechargeBaseWin>())
                UIManager.Instance.CloseWindow<FestivalActivityRechargeBaseWin>();
            UpdateRedPoint();
            onStateUpdate?.Invoke(activityID);
        }
    }
    private void OperationAdvanceEvent(OperationType type)
    {
        if (type == operaType)
        {
            UpdateRedPoint();
            onStateUpdate?.Invoke(activityID);
        }
    }
    public void UpdateRedPoint()
    {
        redPoint.state = RedPointState.None;
        if (!FuncOpen.Instance.IsFuncOpen((int)FuncOpenEnum.OSGala))
            return;
        if (!IsOpen)
            return;
        var awardList = GetShowList();
        if (awardList == null)
            return;
        for (int i = 0; i < awardList.Count; i++)
        {
            if (GetState(awardList[i]) == 1)
            {
                redPoint.state = RedPointState.Simple;
                return;
            }
        }
        var storeData = GetStoreData();
        if (storeData != null && !IsReceived(storeData.shopId))
        {
            redPoint.state = RedPointState.Simple;
        }
    }
    public bool GetActInfo(out OperationTotDayRechargeInfo act, out ActTotDayRechargeConfig config)
    {
        config = null;
        if (!OperationTimeHepler.Instance.TryGetOperation(operaType, out act) || act == null)
            return false;
        config = ActTotDayRechargeConfig.Get(act.CfgID);
        return config != null;
    }
    public List<int> GetShowList(bool isSort = false)
    {
        if (!GetActInfo(out var act, out var config))
            return null;
        int templateID = config.TemplateID;
        var res = new List<int>();
        var awardIndexSortList = ActTotDayRechargeTempConfig.GetNeedDaySortList(templateID);
        for (int i = 0; i < awardIndexSortList.Count; i++)
        {
            var tempConfig = ActTotDayRechargeTempConfig.GetConfig(templateID, awardIndexSortList[i]);
            if (tempConfig == null)
                continue;
            res.Add(tempConfig.AwardID);
        }
        if (isSort)
        {
            res = res.OrderBy(awardId =>
            {
                var tempConfig = ActTotDayRechargeTempConfig.Get(awardId);
                return IsAwardHave(tempConfig.NeedDay);
            })
            .ThenBy(awardId => awardId)
            .ToList();
        }
        return res;
    }
    public bool IsCanBuyShop(int shopID)
    {
        StoreConfig config = StoreConfig.Get(shopID);
        if (config == null)
            return false;
        StoreModel.Instance.TryGetIsSellOut(config, out int remainNum);
        return remainNum > 0;
    }
    public StoreModel.StoreData GetStoreData()
    {
        if (!GetActInfo(out var act, out var config))
            return null;
        int actShopType = config.ActShopType;
        if (StoreModel.Instance.storeTypeDict == null)
            return null;
        if (!StoreModel.Instance.storeTypeDict.TryGetValue(actShopType, out var list))
            return null;
        if (list.IsNullOrEmpty())
            return null;
        return list[0];
    }
    bool IsAwardHave(int awardIndex)
    {
        if (awardIndex < 0 || awardIndex >= 32)
            return false;
        return (awardRecord & (1u << awardIndex)) != 0;
    }
    // 获取奖励状态 0 不可领取 1 未领取 2 已领取
    public int GetState(int awardID)
    {
        var config = ActTotDayRechargeTempConfig.Get(awardID);
        if (config == null)
            return 0;
        if (totalDays < config.NeedDay)
            return 0;
        bool isAwardHave = IsAwardHave(config.NeedDay);
        return isAwardHave ? 2 : 1;
    }
    public bool IsReceived(int shopId)
    {
        var config = StoreConfig.Get(shopId);
        if (config == null)
            return false;
        int boughtCount = StoreModel.Instance.GetShopLimitBuyCount(shopId);
        return boughtCount >= config.LimitCnt;
    }
    public string GetActTimeStr()
    {
        if (!GetActInfo(out var act, out var config))
        {
            return Language.Get("OSActivity6");
        }
        return Language.Get("TotalRecharge08", TimeUtility.SecondsToShortDHMS(act.GetResetSurplusTime()));
    }
    public byte totalDays;    //活动累充天数
    public uint awardRecord;    //累充奖励领奖记录,按奖励索引二进制位存储是否已领取
    public event Action OnTotDayRechargePlayerInfoEvent;
    public void UpdateTotDayRechargePlayerInfo(HAA1A_tagSCActTotDayRechargePlayerInfo vNetData)
    {
        if (ActNum != vNetData.ActNum)
            return;
        totalDays = vNetData.TotalDays;
        awardRecord = vNetData.AwardRecord;
        UpdateRedPoint();
        OnTotDayRechargePlayerInfoEvent?.Invoke();
    }
    public void SendGetReward(int needDay)
    {
        string actStr = ActNum.ToString();
        var pack = new CA504_tagCMPlayerGetReward();
        pack.RewardType = 19;
        pack.DataEx = (uint)needDay;
        pack.DataExStr = actStr;
        pack.DataExStrLen = (byte)actStr.Length;
        GameNetSystem.Instance.SendInfo(pack);
    }
}
Main/System/FestivalActivity/FestivalActivityRechargeTotDayManager.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0625bbc16a0d77046b6393549c59b91a
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/FestivalActivityRechargeTotDayWin.cs
New file
@@ -0,0 +1,113 @@
using System.Collections.Generic;
using UnityEngine;
//开服活动-累充
public class FestivalActivityRechargeTotDayWin : UIBase
{
    [SerializeField] ItemCell totDayRechargeItemCell;
    [SerializeField] TextEx totDayRechargeScoreText;
    [SerializeField] RotationTween totDayRechargeRotationTween;
    [SerializeField] ImageEx totDayRechargeFreeRedImage;
    [SerializeField] ImageEx totDayRechargeHaveImage;
    [SerializeField] ScrollerController scroller;
    FestivalActivityRechargeTotDayManager manager { get { return FestivalActivityRechargeTotDayManager.Instance; } }
    protected override void OnPreOpen()
    {
        scroller.OnRefreshCell += OnRefreshCell;
        manager.OnTotDayRechargePlayerInfoEvent += OnTotDayRechargePlayerInfoEvent;
        StoreModel.Instance.RefreshBuyShopLimitEvent += OnRefreshBuyShopLimitEvent;
        CreateScroller();
        InitRechargeData();
    }
    protected override void OnPreClose()
    {
        scroller.OnRefreshCell -= OnRefreshCell;
        manager.OnTotDayRechargePlayerInfoEvent -= OnTotDayRechargePlayerInfoEvent;
        StoreModel.Instance.RefreshBuyShopLimitEvent -= OnRefreshBuyShopLimitEvent;
    }
    private void OnRefreshBuyShopLimitEvent()
    {
        scroller.m_Scorller.RefreshActiveCellViews();
        RefreshRechargeData();
    }
    private void OnTotDayRechargePlayerInfoEvent()
    {
        scroller.m_Scorller.RefreshActiveCellViews();
        RefreshRechargeData();
    }
    void InitRechargeData()
    {
        var data = manager.GetStoreData();
        bool isReceived = manager.IsReceived(data.shopId);
        totDayRechargeItemCell.Init(new ItemCellModel(data.storeConfig.ItemID, false, data.storeConfig.ItemCnt));
        totDayRechargeItemCell.button.SetListener(() =>
        {
            if (!isReceived)
            {
                StoreModel.Instance.SendBuyShopItem(data.storeConfig, 1);
            }
            else
            {
                ItemTipUtility.Show(data.storeConfig.ItemID);
            }
        });
        totDayRechargeHaveImage.SetActive(isReceived);
        totDayRechargeFreeRedImage.SetActive(!isReceived);
        totDayRechargeScoreText.text = Language.Get("TotalRecharge07", manager.totalDays);
        if (!isReceived)
        {
            totDayRechargeRotationTween.Play();
        }
        else
        {
            totDayRechargeRotationTween.Stop();
            totDayRechargeRotationTween.SetStartState();
        }
    }
    void RefreshRechargeData()
    {
        var data = manager.GetStoreData();
        bool isReceived = manager.IsReceived(data.shopId);
        totDayRechargeItemCell.Init(new ItemCellModel(data.storeConfig.ItemID, false, data.storeConfig.ItemCnt));
        totDayRechargeHaveImage.SetActive(isReceived);
        totDayRechargeFreeRedImage.SetActive(!isReceived);
        totDayRechargeScoreText.text = Language.Get("TotalRecharge07", manager.totalDays);
        if (!isReceived)
        {
            totDayRechargeRotationTween.Play();
        }
        else
        {
            totDayRechargeRotationTween.Stop();
            totDayRechargeRotationTween.SetStartState();
        }
    }
    List<int> showList;
    void CreateScroller()
    {
        showList = manager.GetShowList(true);
        scroller.Refresh();
        for (int i = 0; i < showList.Count; i++)
        {
            scroller.AddCell(ScrollerDataType.Header, i);
        }
        scroller.Restart();
    }
    void OnRefreshCell(ScrollerDataType type, CellView cell)
    {
        var _cell = cell as FestivalActivityRechargeTotDayCell;
        _cell.Display(cell.index, showList);
    }
}
Main/System/FestivalActivity/FestivalActivityRechargeTotDayWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6f977063d346b8f4881b912d1243fbdb
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/FestivalActivityRechargeTotalCell.cs
New file
@@ -0,0 +1,74 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class FestivalActivityRechargeTotalCell : CellView
{
    [SerializeField] Text nameText;
    [SerializeField] Image processImage;
    [SerializeField] Text processText;
    [SerializeField] ItemCell[] itemCells;
    [SerializeField] Button getBtn;
    [SerializeField] Button gotoBtn;
    [SerializeField] Transform gotRect;
    FestivalActivityRechargeTotalManager manager { get { return FestivalActivityRechargeTotalManager.Instance; } }
    public void Display(int index, List<int> list)
    {
        if (list.IsNullOrEmpty() || index < 0 || index >= list.Count)
            return;
        int awardID = list[index];
        var config = ActTotalRechargeTempConfig.Get(awardID);
        if (config == null)
            return;
        nameText.text = Language.Get($"TotalRecharge02", config.NeedAmount);
        if (config.AwardItemList != null)
        {
            for (int i = 0; i < itemCells.Length; i++)
            {
                var cell = itemCells[i];
                if (i < config.AwardItemList.Length)
                {
                    var item = config.AwardItemList[i];
                    cell.SetActive(true);
                    cell.Init(new ItemCellModel(item[0], false, item[1]));
                    cell.button.AddListener(() => ItemTipUtility.Show(item[0]));
                }
                else
                {
                    cell.SetActive(false);
                }
            }
        }
        processText.text = Language.Get("BoneField09", manager.coinTotal, config.NeedAmount);
        processImage.fillAmount = manager.coinTotal / (float)config.NeedAmount;
        int state = manager.GetState(awardID);// 获取奖励状态 0 不可领取 1 未领取 2 已领取
        gotoBtn.SetActive(state == 0);
        getBtn.SetActive(state == 1);
        gotRect.SetActive(state == 2);
        getBtn.SetListener(() => manager.SendGetReward(config.AwardIndex));
        gotoBtn.SetListener(() =>
        {
            if (FuncOpen.Instance.IsFuncOpen((int)FuncOpenEnum.Recharge, true))
            {
                RechargeManager.Instance.selectTabIndex = 1;
                if (UIManager.Instance.IsOpened<StoreBaseWin>())
                {
                    UIManager.Instance.GetUI<StoreBaseWin>().ClickFuncBtn(2);
                }
                else
                {
                    UIManager.Instance.OpenWindow<StoreBaseWin>(2);
                }
            }
        });
    }
}
Main/System/FestivalActivity/FestivalActivityRechargeTotalCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 57f1d393b81fe04409bfc2fd5e5ecebc
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/FestivalActivityRechargeTotalManager.cs
New file
@@ -0,0 +1,249 @@
using System;
using System.Collections.Generic;
using System.Linq;
public class FestivalActivityRechargeTotalManager : GameSystemManager<FestivalActivityRechargeTotalManager>, IOpenServerActivity
{
    public readonly int ActNum = 30;
    public override void Init()
    {
        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEventOnRelogin += OnBeforePlayerDataInitializeEventOnRelogin;
        OperationTimeHepler.Instance.operationTimeUpdateEvent += OperationTimeUpdateEvent;
        OperationTimeHepler.Instance.operationStartEvent += OperationStartEvent;
        OperationTimeHepler.Instance.operationEndEvent += OperationEndEvent;
        OperationTimeHepler.Instance.operationAdvanceEvent += OperationAdvanceEvent;
        FuncOpen.Instance.OnFuncStateChangeEvent += OnFuncStateChangeEvent;
        StoreModel.Instance.RefreshBuyShopLimitEvent += OnRefreshBuyShopLimitEvent;
    }
    public override void Release()
    {
        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEventOnRelogin -= OnBeforePlayerDataInitializeEventOnRelogin;
        OperationTimeHepler.Instance.operationTimeUpdateEvent -= OperationTimeUpdateEvent;
        OperationTimeHepler.Instance.operationStartEvent -= OperationStartEvent;
        OperationTimeHepler.Instance.operationEndEvent -= OperationEndEvent;
        OperationTimeHepler.Instance.operationAdvanceEvent -= OperationAdvanceEvent;
        FuncOpen.Instance.OnFuncStateChangeEvent -= OnFuncStateChangeEvent;
        StoreModel.Instance.RefreshBuyShopLimitEvent -= OnRefreshBuyShopLimitEvent;
    }
    private void OnRefreshBuyShopLimitEvent()
    {
        UpdateRedPoint();
    }
    private void OnFuncStateChangeEvent(int obj)
    {
        if (obj != (int)FuncOpenEnum.FestivalActivity)
            return;
        UpdateRedPoint();
    }
    private void OnBeforePlayerDataInitializeEventOnRelogin()
    {
        coinTotal = 0;
        awardRecord = 0;
    }
    public const int activityType = (int)OpenServerActivityCenter.ActivityType.AT_DateActivity;
    public const int activityID = (int)NewDayActivityID.FestivalActivityRechargeTotalAct;
    public static OperationType operaType = OperationType.FestivalActivity_RechargeTotal;
    // 总奖励
    public Redpoint redPoint = new Redpoint(
        FestivalActivityManager.Instance.GetRedPointId(FestivalActivityRepointType.Recharge),
        FestivalActivityManager.Instance.GetRedPointId(FestivalActivityRepointType.TotalRecharge));
    public bool IsOpen => OperationTimeHepler.Instance.SatisfyOpenCondition(operaType);
    public bool IsAdvance => OperationTimeHepler.Instance.SatisfyAdvanceCondition(operaType);
    public bool priorityOpen => redPoint.state == RedPointState.Simple;
    public event Action<int> onStateUpdate;
    private void OperationTimeUpdateEvent(OperationType type)
    {
        if (UIManager.Instance.IsOpened<FestivalActivityRechargeBaseWin>())
            UIManager.Instance.CloseWindow<FestivalActivityRechargeBaseWin>();
        UpdateRedPoint();
    }
    private void OperationStartEvent(OperationType type, int state)
    {
        if (type == operaType && state == 0)
        {
            UpdateRedPoint();
            onStateUpdate?.Invoke(activityID);
        }
    }
    private void OperationEndEvent(OperationType type, int state)
    {
        if (type == operaType)
        {
            if (UIManager.Instance.IsOpened<FestivalActivityRechargeBaseWin>())
                UIManager.Instance.CloseWindow<FestivalActivityRechargeBaseWin>();
            UpdateRedPoint();
            onStateUpdate?.Invoke(activityID);
        }
    }
    private void OperationAdvanceEvent(OperationType type)
    {
        if (type == operaType)
        {
            UpdateRedPoint();
            onStateUpdate?.Invoke(activityID);
        }
    }
    public void UpdateRedPoint()
    {
        redPoint.state = RedPointState.None;
        if (!FuncOpen.Instance.IsFuncOpen((int)FuncOpenEnum.FestivalActivity))
            return;
        if (!IsOpen)
            return;
        var awardList = GetShowList();
        if (awardList == null)
            return;
        for (int i = 0; i < awardList.Count; i++)
        {
            if (GetState(awardList[i]) == 1)
            {
                redPoint.state = RedPointState.Simple;
                return;
            }
        }
        var storeData = GetStoreData();
        if (storeData != null && !IsReceived(storeData.shopId))
        {
            redPoint.state = RedPointState.Simple;
        }
    }
    public bool GetActInfo(out OperationTotalRechargeInfo act, out ActTotalRechargeConfig config)
    {
        config = null;
        if (!OperationTimeHepler.Instance.TryGetOperation(operaType, out act) || act == null)
            return false;
        config = ActTotalRechargeConfig.Get(act.CfgID);
        return config != null;
    }
    public List<int> GetShowList(bool isSort = false)
    {
        if (!GetActInfo(out var act, out var config))
            return null;
        int ctgTempID = config.CTGTempID;
        int ctgShopType = config.CTGShopType;
        var res = new List<int>();
        var awardIndexSortList = ActTotalRechargeTempConfig.GetAwardIndexSortList(ctgTempID);
        for (int i = 0; i < awardIndexSortList.Count; i++)
        {
            var tempConfig = ActTotalRechargeTempConfig.GetConfig(ctgTempID, awardIndexSortList[i]);
            if (tempConfig == null)
                continue;
            res.Add(tempConfig.AwardID);
        }
        if (isSort)
        {
            res = res.OrderBy(awardId =>
            {
                var tempConfig = ActTotalRechargeTempConfig.Get(awardId);
                return IsAwardHave(tempConfig.AwardIndex);
            })
            .ThenBy(awardId => awardId)
            .ToList();
        }
        return res;
    }
    public bool IsCanBuyShop(int shopID)
    {
        StoreConfig config = StoreConfig.Get(shopID);
        if (config == null)
            return false;
        StoreModel.Instance.TryGetIsSellOut(config, out int remainNum);
        return remainNum > 0;
    }
    public StoreModel.StoreData GetStoreData()
    {
        if (!GetActInfo(out var act, out var config))
            return null;
        int ctgShopType = config.CTGShopType;
        if (StoreModel.Instance.storeTypeDict == null)
            return null;
        if (!StoreModel.Instance.storeTypeDict.TryGetValue(ctgShopType, out var list))
            return null;
        if (list.IsNullOrEmpty())
            return null;
        return list[0];
    }
    public float coinTotal;    //活动累计充值额coin值
    public uint awardRecord;    //累充奖励领奖记录,按奖励索引二进制位存储是否已领取
    public event Action OnTotalRechargePlayerInfoEvent;
    public void UpdateTotalRechargePlayerInfo(HAA1C_tagSCActTotalRechargePlayerInfo vNetData)
    {
        if (ActNum != vNetData.ActNum)
            return;
        coinTotal = (float)vNetData.CoinTotal / (float)100;
        awardRecord = vNetData.AwardRecord;
        UpdateRedPoint();
        OnTotalRechargePlayerInfoEvent?.Invoke();
    }
    bool IsAwardHave(int awardIndex)
    {
        if (awardIndex < 0 || awardIndex >= 32)
            return false;
        return (awardRecord & (1u << awardIndex)) != 0;
    }
    // 获取奖励状态 0 不可领取 1 未领取 2 已领取
    public int GetState(int awardID)
    {
        var config = ActTotalRechargeTempConfig.Get(awardID);
        if (config == null)
            return 0;
        if (coinTotal < config.NeedAmount)
            return 0;
        bool isAwardHave = IsAwardHave(config.AwardIndex);
        return isAwardHave ? 2 : 1;
    }
    public bool IsReceived(int shopId)
    {
        var config = StoreConfig.Get(shopId);
        if (config == null)
            return false;
        int boughtCount = StoreModel.Instance.GetShopLimitBuyCount(shopId);
        return boughtCount >= config.LimitCnt;
    }
    public string GetActTimeStr()
    {
        if (!GetActInfo(out var act, out var config))
        {
            return Language.Get("OSActivity6");
        }
        return Language.Get("TotalRecharge08", TimeUtility.SecondsToShortDHMS(act.GetResetSurplusTime()));
    }
    public void SendGetReward(int awardIndex)
    {
        string actStr = ActNum.ToString();
        var pack = new CA504_tagCMPlayerGetReward();
        pack.RewardType = 18;
        pack.DataEx = (uint)awardIndex;
        pack.DataExStr = actStr;
        pack.DataExStrLen = (byte)actStr.Length;
        GameNetSystem.Instance.SendInfo(pack);
    }
}
Main/System/FestivalActivity/FestivalActivityRechargeTotalManager.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bcf0ceb7f1a7c8245afc8842e15ce2a3
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/FestivalActivityRechargeTotalWin.cs
New file
@@ -0,0 +1,118 @@
using System;
using System.Collections.Generic;
using UnityEngine;
public class FestivalActivityRechargeTotalWin : UIBase
{
    [SerializeField] ItemCell totalRechargeItemCell;
    [SerializeField] TextEx totalRechargeScoreText;
    [SerializeField] RotationTween totalRechargeRotationTween;
    [SerializeField] ImageEx totalRechargeFreeRedImage;
    [SerializeField] ImageEx totalRechargeHaveImage;
    [SerializeField] ScrollerController scroller;
    FestivalActivityRechargeTotalManager manager { get { return FestivalActivityRechargeTotalManager.Instance; } }
    protected override void OnPreOpen()
    {
        scroller.OnRefreshCell += OnRefreshCell;
        manager.OnTotalRechargePlayerInfoEvent += OnTotalRechargePlayerInfoEvent;
        StoreModel.Instance.RefreshBuyShopLimitEvent += OnRefreshBuyShopLimitEvent;
        CreateScroller();
        InitRechargeData();
    }
    protected override void OnPreClose()
    {
        scroller.OnRefreshCell -= OnRefreshCell;
        manager.OnTotalRechargePlayerInfoEvent -= OnTotalRechargePlayerInfoEvent;
        StoreModel.Instance.RefreshBuyShopLimitEvent -= OnRefreshBuyShopLimitEvent;
    }
    private void OnRefreshBuyShopLimitEvent()
    {
        scroller.m_Scorller.RefreshActiveCellViews();
        RefreshRechargeData();
    }
    private void OnTotalRechargePlayerInfoEvent()
    {
        scroller.m_Scorller.RefreshActiveCellViews();
        RefreshRechargeData();
    }
    void InitRechargeData()
    {
        var data = manager.GetStoreData();
        bool isReceived = manager.IsReceived(data.shopId);
        totalRechargeItemCell.Init(new ItemCellModel(data.storeConfig.ItemID, false, data.storeConfig.ItemCnt));
        totalRechargeItemCell.button.SetListener(() =>
        {
            if (!isReceived)
            {
                StoreModel.Instance.SendBuyShopItem(data.storeConfig, 1);
            }
            else
            {
                ItemTipUtility.Show(data.storeConfig.ItemID);
            }
        });
        totalRechargeHaveImage.SetActive(isReceived);
        totalRechargeFreeRedImage.SetActive(!isReceived);
        totalRechargeScoreText.text = Language.Get("TotalRecharge06", manager.coinTotal);
        if (!isReceived)
        {
            totalRechargeRotationTween.Play();
        }
        else
        {
            totalRechargeRotationTween.Stop();
            totalRechargeRotationTween.SetStartState();
        }
    }
    void RefreshRechargeData()
    {
        var data = manager.GetStoreData();
        bool isReceived = manager.IsReceived(data.shopId);
        totalRechargeItemCell.Init(new ItemCellModel(data.storeConfig.ItemID, false, data.storeConfig.ItemCnt));
        totalRechargeHaveImage.SetActive(isReceived);
        totalRechargeFreeRedImage.SetActive(!isReceived);
        totalRechargeScoreText.text = Language.Get("TotalRecharge06", manager.coinTotal);
        if (!isReceived)
        {
            totalRechargeRotationTween.Play();
        }
        else
        {
            totalRechargeRotationTween.Stop();
            totalRechargeRotationTween.SetStartState();
        }
    }
    List<int> showList;
    void CreateScroller()
    {
        showList = manager.GetShowList(true);
        scroller.Refresh();
        for (int i = 0; i < showList.Count; i++)
        {
            scroller.AddCell(ScrollerDataType.Header, i);
        }
        scroller.Restart();
    }
    void OnRefreshCell(ScrollerDataType type, CellView cell)
    {
        var _cell = cell as FestivalActivityRechargeTotalCell;
        _cell.Display(cell.index, showList);
    }
}
Main/System/FestivalActivity/FestivalActivityRechargeTotalWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1a033d0838bfdfb468b0885f494be34b
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/FestivalActivityShopCell.cs
New file
@@ -0,0 +1,132 @@
using UnityEngine;
using UnityEngine.UI;
public class FestivalActivityShopCell : MonoBehaviour
{
    [SerializeField] Transform saleRect;
    [SerializeField] Text saleText;
    [SerializeField] Text itemName;
    [SerializeField] ItemCell itemCell;
    [SerializeField] Text limitText;
    [SerializeField] Text lockTip;
    [SerializeField] Transform priceRect;
    [SerializeField] Image priceIcon;
    [SerializeField] Text priceText;
    [SerializeField] Transform priceRect1;//居中位置的价格
    [SerializeField] Image priceIcon1;
    [SerializeField] Text priceText1;
    [SerializeField] Transform salePriceRect;
    [SerializeField] Text salePriceText;
    [SerializeField] Button buyButton;
    [SerializeField] Image freeRedPoint;
    [SerializeField] Text freeText;
    [SerializeField] Image exclusiveImage;//专属
    [SerializeField] Image sellOutImage;//售罄
    FestivalActivityMissionManager manager => FestivalActivityMissionManager.Instance;
    public void Display(int index)
    {
        ActTaskConfig config = manager.GetCurrentConfig();
        if (config == null)
            return;
        if (!StoreModel.Instance.storeTypeDict.TryGetValue(config.ActShopTypeEx, out var list))
            return;
        var storeData = list[index];
        int shopID = storeData.shopId;
        var itemID = storeData.storeConfig.ItemID;
        var itemCount = storeData.storeConfig.ItemCnt;
        exclusiveImage.SetActive(storeData.storeConfig.IsExclusive == 1);
        itemCell.Init(new ItemCellModel(itemID, false, itemCount));
        itemCell.button.AddListener(() =>
        {
            ItemTipUtility.Show(itemID);
        });
        var itemConfig = ItemConfig.Get(itemID);
        itemName.text = itemConfig.ItemName;
        //折扣
        if (storeData.storeConfig.MoneyOriginal != 0)
        {
            saleRect.SetActive(true);
            saleText.text = Language.Get("storename5", (storeData.storeConfig.MoneyNum * 10 / (float)storeData.storeConfig.MoneyOriginal).ToString("0.#"));
        }
        else
        {
            saleRect.SetActive(false);
        }
        var buyCnt = StoreModel.Instance.GetShopLimitBuyCount(shopID);
        string limitStr = "";
        if (storeData.storeConfig.MoneyNum == 0)
        {
            //免费
            limitStr = "";
        }
        else if (storeData.storeConfig.ResetType == 0)
        {
            //限购
            limitStr = storeData.storeConfig.LimitCnt > 0 ? Language.Get("storename8", storeData.storeConfig.LimitCnt - buyCnt, storeData.storeConfig.LimitCnt) : "";
        }
        else if (storeData.storeConfig.ResetType == 1)
        {
            //每日限购
            limitStr = Language.Get("storename6", storeData.storeConfig.LimitCnt - buyCnt, storeData.storeConfig.LimitCnt);
        }
        else if (storeData.storeConfig.ResetType == 2)
        {
            //每周限购
            limitStr = Language.Get("storename7", storeData.storeConfig.LimitCnt - buyCnt, storeData.storeConfig.LimitCnt);
        }
        limitText.text = buyCnt >= storeData.storeConfig.LimitCnt ? UIHelper.AppendColor(TextColType.Gray, limitStr) : limitStr;
        buyButton.AddListener(() => { BuyGoods(shopID); });
        //0可购买 1已售罄 2免费 3未解锁
        var state = StoreModel.Instance.GetShopIDState(shopID);
        sellOutImage.SetActive(state == 1);
        freeRedPoint.SetActive(state == 2);
        lockTip.text = state == 3 ? Language.Get("storename10", storeData.storeConfig.UnlockValue) : string.Empty;
        priceRect.SetActive((state == 0 || state == 3) && storeData.storeConfig.MoneyOriginal != 0);
        priceRect1.SetActive((state == 0 || state == 3) && storeData.storeConfig.MoneyOriginal == 0);
        freeText.SetActive(state == 2 || (state == 1 && storeData.storeConfig.MoneyOriginal == 0));
        salePriceRect.SetActive((state == 0 || state == 3) && storeData.storeConfig.MoneyOriginal != 0);
        priceText.text = storeData.storeConfig.MoneyNum.ToString();
        priceText1.text = storeData.storeConfig.MoneyNum.ToString();
        if (storeData.storeConfig.MoneyType <= 0)
        {
            priceIcon.SetItemSprite(storeData.storeConfig.CostItemID);
            priceIcon1.SetItemSprite(storeData.storeConfig.CostItemID);
        }
        else
        {
            priceIcon.SetIconWithMoneyType(storeData.storeConfig.MoneyType);
            priceIcon1.SetIconWithMoneyType(storeData.storeConfig.MoneyType);
        }
        salePriceText.text = storeData.storeConfig.MoneyOriginal.ToString();
    }
    void BuyGoods(int shopID)
    {
        var state = StoreModel.Instance.GetShopIDState(shopID);
        if (state == 1) return;
        if (state == 2)
        {
            StoreModel.Instance.SendBuyShopItem(StoreConfig.Get(shopID), 1);
        }
        else
        {
            StoreModel.Instance.buyShopID = shopID;
            UIManager.Instance.OpenWindow<BuyItemWin>();
        }
    }
}
Main/System/FestivalActivity/FestivalActivityShopCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1ab9f2879e44d2a42ab352d11f5254fd
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/FestivalActivityShopLineCell.cs
New file
@@ -0,0 +1,28 @@
using UnityEngine;
public class FestivalActivityShopLineCell : CellView
{
    [SerializeField] FestivalActivityShopCell[] storeCells;
    FestivalActivityMissionManager manager => FestivalActivityMissionManager.Instance;
    public void Display(int index)
    {
        ActTaskConfig config = manager.GetCurrentConfig();
        if (config == null)
            return;
        if (!StoreModel.Instance.storeTypeDict.TryGetValue(config.ActShopTypeEx, out var list))
            return;
        for (int i = 0; i < storeCells.Length; i++)
        {
            if (index + i < list.Count)
            {
                storeCells[i].SetActive(true);
                storeCells[i].Display(index + i);
            }
            else
            {
                storeCells[i].SetActive(false);
            }
        }
    }
}
Main/System/FestivalActivity/FestivalActivityShopLineCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6bd33c42e26241b47987559017eaa303
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/FestivalActivityShopWin.cs
New file
@@ -0,0 +1,83 @@
using UnityEngine;
public class FestivalActivityShopWin : UIBase
{
    [SerializeField] OwnItemCell ownItemCell;
    [SerializeField] ButtonEx closeButton;
    [SerializeField] TextEx timeText;
    [SerializeField] ScrollerController scroller;
    FestivalActivityMissionManager manager => FestivalActivityMissionManager.Instance;
    protected override void InitComponent()
    {
        closeButton.SetListener(CloseWindow);
    }
    protected override void OnPreOpen()
    {
        scroller.OnRefreshCell += OnRefreshCell;
        StoreModel.Instance.RefreshShopEvent += CreateScroller;
        StoreModel.Instance.RefreshBuyShopLimitEvent += CreateScroller;
        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
        if (!manager.IsShopVisitedToday)
        {
            manager.SaveShopVisitTimeData();
            manager.UpdateRedPoint();
        }
        ActTaskConfig config = manager.GetCurrentConfig();
        if (config == null)
            return;
        ownItemCell.itemID = config.ActScoreItemID;
        CreateScroller();
        OnSecondEvent();
    }
    protected override void OnPreClose()
    {
        scroller.OnRefreshCell -= OnRefreshCell;
        StoreModel.Instance.RefreshShopEvent -= CreateScroller;
        StoreModel.Instance.RefreshBuyShopLimitEvent -= CreateScroller;
        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
        StoreModel.Instance.selectStoreFuncType = StoreFunc.Normal;
    }
    void OnRefreshCell(ScrollerDataType type, CellView cell)
    {
        var _cell = cell as FestivalActivityShopLineCell;
        _cell.Display(cell.index);
    }
    private void OnSecondEvent()
    {
        if (!OperationTimeHepler.Instance.TryGetOperation(OperationType.FestivalActivity_Mission, out OperationMissionActivityInfo operation))
        {
            timeText.text = Language.Get("OSActivity6");
            return;
        }
        timeText.text = Language.Get("TimeRush05", TimeUtility.SecondsToShortDHMS(operation.GetResetSurplusTime()));
    }
    void CreateScroller()
    {
        ActTaskConfig config = manager.GetCurrentConfig();
        if (config == null)
            return;
        if (!StoreModel.Instance.storeTypeDict.TryGetValue(config.ActShopTypeEx, out var list))
            return;
        scroller.Refresh();
        for (int i = 0; i < list.Count; i++)
        {
            if (i % 3 == 0)
            {
                scroller.AddCell(ScrollerDataType.Header, i);
            }
        }
        scroller.Restart();
        scroller.lockType = EnhanceLockType.KeepVertical;
    }
}
Main/System/FestivalActivity/FestivalActivityShopWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f29a66f9d8794c342bce21767d912ecd
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/FestivalActivityWin.cs
New file
@@ -0,0 +1,79 @@
using UnityEngine;
public class FestivalActivityWin : UIBase
{
    [SerializeField] ImageEx bgImage;
    [SerializeField] TextEx timeText;
    [SerializeField] ButtonEx closeButton;
    [SerializeField] ButtonEx checkInButton;
    [SerializeField] ButtonEx missionButton;
    [SerializeField] ButtonEx shopButton;
    [SerializeField] ButtonEx giftButton;
    [SerializeField] ButtonEx rechargeButton;
    [SerializeField] ButtonEx previewButton;
    [SerializeField] RedpointBehaviour checkInRedpoint;
    [SerializeField] RedpointBehaviour missionRedpoint;
    [SerializeField] RedpointBehaviour shopRedpoint;
    [SerializeField] RedpointBehaviour giftRedpoint;
    [SerializeField] RedpointBehaviour rechargeRedpoint;
    FestivalActivityManager manager => FestivalActivityManager.Instance;
    protected override void InitComponent()
    {
        closeButton.SetListener(() => UIManager.Instance.CloseWindow<FestivalActivityWin>());
        checkInButton.SetListener(() => UIManager.Instance.OpenWindow<FestivalActivityCheckInWin>());
        missionButton.SetListener(() => UIManager.Instance.OpenWindow<FestivalActivityMissionWin>());
        shopButton.SetListener(() => UIManager.Instance.OpenWindow<FestivalActivityShopWin>());
        giftButton.SetListener(() => UIManager.Instance.OpenWindow<FestivalActivityGiftWin>());
        rechargeButton.SetListener(() => UIManager.Instance.OpenWindow<FestivalActivityRechargeBaseWin>());
    }
    protected override void OnPreOpen()
    {
        InitRedpoint();
        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
        RechargeManager.Instance.rechargeCountEvent += OnRechargeCountEvent;
        StoreModel.Instance.RefreshBuyShopLimitEvent += Display;
        Display();
    }
    protected override void OnPreClose()
    {
        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
        RechargeManager.Instance.rechargeCountEvent -= OnRechargeCountEvent;
        StoreModel.Instance.RefreshBuyShopLimitEvent -= Display;
    }
    private void OnRechargeCountEvent(int obj)
    {
        Display();
    }
    public void InitRedpoint()
    {
        checkInRedpoint.redpointId = manager.GetRedPointId(FestivalActivityRepointType.CheckIn);
        missionRedpoint.redpointId = manager.GetRedPointId(FestivalActivityRepointType.Mission);
        shopRedpoint.redpointId = manager.GetRedPointId(FestivalActivityRepointType.Shop);
        giftRedpoint.redpointId = manager.GetRedPointId(FestivalActivityRepointType.Gift);
        rechargeRedpoint.redpointId = manager.GetRedPointId(FestivalActivityRepointType.Recharge);
    }
    private void Display()
    {
        OnSecondEvent();
    }
    private void OnSecondEvent()
    {
        var act = manager.GetActInfo();
        if (act == null)
        {
            timeText.text = Language.Get("OSActivity6");
            return;
        }
        timeText.text = Language.Get("FestivalActivity02", act.ToDisplayTimeEx(), TimeUtility.SecondsToShortDHMS(act.GetResetSurplusTime()));
    }
}
Main/System/FestivalActivity/FestivalActivityWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bd54e7e15919c3a409eab1cb99dbfab5
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/OperationCheckInActivityInfo.cs
New file
@@ -0,0 +1,23 @@
public class OperationCheckInActivityInfo : OperationBase
{
    public int ActType; // 活动类型,用于关联活动相关模块用,如签到、任务等
    public int CfgID;   // 活动时间表配置ID
    public override string ToDisplayTime()
    {
        var textBuilder = OperationTimeHepler.textBuilder;
        textBuilder.Length = 0;
        textBuilder.Append(startDate.ToDisplay(false));
        textBuilder.Append(" 00:00:00");
        if (startDate != endDate)
        {
            textBuilder.Append("-");
            textBuilder.Append(endDate.ToDisplay(false));
            textBuilder.Append(" 23:59:59");
        }
        return textBuilder.ToString();
    }
}
Main/System/FestivalActivity/OperationCheckInActivityInfo.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: df08f6c5862454d4c8a24d44af3a84f0
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/OperationFlashSaleActivityInfo.cs
New file
@@ -0,0 +1,34 @@
public class OperationFlashSaleActivityInfo : OperationBase
{
    public int ActType; // 活动类型,用于关联活动相关模块用,如签到、任务等
    public int CfgID;   // 活动时间表配置ID
    public override string ToDisplayTime()
    {
        var textBuilder = OperationTimeHepler.textBuilder;
        textBuilder.Length = 0;
        textBuilder.Append(startDate.ToDisplay(false));
        textBuilder.Append(" 00:00:00");
        if (startDate != endDate)
        {
            textBuilder.Append("-");
            textBuilder.Append(endDate.ToDisplay(false));
            textBuilder.Append(" 23:59:59");
        }
        return textBuilder.ToString();
    }
    public string ToDisplayTimeEx()
    {
        var textBuilder = OperationTimeHepler.textBuilder;
        textBuilder.Length = 0;
        textBuilder.Append(startDate.ToDisplay(false));
        if (startDate != endDate)
        {
            textBuilder.Append("-");
            textBuilder.Append(endDate.ToDisplay(false));
        }
        return textBuilder.ToString();
    }
}
Main/System/FestivalActivity/OperationFlashSaleActivityInfo.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 546d13d472461714fa4e45fd54742409
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/FestivalActivity/OperationMissionActivityInfo.cs
New file
@@ -0,0 +1,23 @@
public class OperationMissionActivityInfo : OperationBase
{
    public int ActType; // 活动类型,用于关联活动相关模块用,如签到、任务等
    public int CfgID;   // 活动时间表配置ID
    public override string ToDisplayTime()
    {
        var textBuilder = OperationTimeHepler.textBuilder;
        textBuilder.Length = 0;
        textBuilder.Append(startDate.ToDisplay(false));
        textBuilder.Append(" 00:00:00");
        if (startDate != endDate)
        {
            textBuilder.Append("-");
            textBuilder.Append(endDate.ToDisplay(false));
            textBuilder.Append(" 23:59:59");
        }
        return textBuilder.ToString();
    }
}
Main/System/FestivalActivity/OperationMissionActivityInfo.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: afebd8558abc1734fbb2a360b7da975c
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroDebut/HeroDebutCallRateItem.cs
@@ -46,7 +46,7 @@
        if (list == null) return;
        if (xbGridArr == null) return;
        if (xbGridArr.Contains(grid))
        if (AreAllLibItemsRelatedToHeroes(list))
        {
            int heroID = manager.GetCurrentDisplayCallHeroId();
            if (!TryGetHeroItemInfo(heroID, libID, list, out int itemID, out int itemCount)) return;
@@ -85,6 +85,38 @@
        return res;
    }
    /// <summary>
    /// 检查库中所有物品是否都与ActHeroReturnArtConfig中的武将相关
    /// </summary>
    private bool AreAllLibItemsRelatedToHeroes(List<int> itemList)
    {
        if (itemList == null || itemList.Count == 0) return false;
        List<int> heroIdList = ActHeroAppearArtConfig.GetKeys();
        if (heroIdList == null || heroIdList.Count == 0) return false;
        for (int i = 0; i < itemList.Count; i++)
        {
            int itemID = itemList[i];
            var config = ItemConfig.Get(itemID);
            if (config == null) return false;
            if (config.Type == 150)
            {
                if (!heroIdList.Contains(itemID)) return false;
            }
            else if (config.Type == 151)
            {
                if (!heroIdList.Contains(config.EffectValueA1)) return false;
            }
            else
            {
                return false;
            }
        }
        return true;
    }
    public bool TryGetHeroItemInfo(int heroID, int libID, List<int> itemList, out int itemID, out int itemCount)
    {
        itemID = 0;
Main/System/HeroReturn/HeroReturnCallRateItem.cs
@@ -46,7 +46,7 @@
        if (list == null) return;
        if (xbGridArr == null) return;
        if (xbGridArr.Contains(grid))
        if (AreAllLibItemsRelatedToHeroes(list))
        {
            int heroID = manager.GetCurrentDisplayCallHeroId();
            if (!TryGetHeroItemInfo(heroID, libID, list, out int itemID, out int itemCount)) return;
@@ -85,6 +85,38 @@
        return res;
    }
    /// <summary>
    /// 检查库中所有物品是否都与ActHeroReturnArtConfig中的武将相关
    /// </summary>
    private bool AreAllLibItemsRelatedToHeroes(List<int> itemList)
    {
        if (itemList == null || itemList.Count == 0) return false;
        List<int> heroIdList = ActHeroReturnArtConfig.GetKeys();
        if (heroIdList == null || heroIdList.Count == 0) return false;
        for (int i = 0; i < itemList.Count; i++)
        {
            int itemID = itemList[i];
            var config = ItemConfig.Get(itemID);
            if (config == null) return false;
            if (config.Type == 150)
            {
                if (!heroIdList.Contains(itemID)) return false;
            }
            else if (config.Type == 151)
            {
                if (!heroIdList.Contains(config.EffectValueA1)) return false;
            }
            else
            {
                return false;
            }
        }
        return true;
    }
    public bool TryGetHeroItemInfo(int heroID, int libID, List<int> itemList, out int itemID, out int itemCount)
    {
        itemID = 0;
Main/System/HeroReturn/HeroReturnZhanLingWin.cs
@@ -120,7 +120,7 @@
        var needCount = zhanLingModel.GetLuckValueAward(config.ActTreasureType) - zhanLingModel.subVulue;
        itemNameText.text = Language.Get("HeroReturnZhanLing01", needCount);
        int heroID = zhanLingModel.GetCurrentDisplayCallHeroId();
        int heroID = zhanLingModel.GetFirstHeroId();
        adImg.SetSprite($"HeroReturnZhanLingBG_{heroID}");
        adWordImg.SetSprite($"HeroReturnZhanLingWord_{heroID}");
        adHeroImg.SetSprite($"HeroReturnZhanLingHero_{heroID}");
Main/System/Horse/HorseController.cs
@@ -1,6 +1,5 @@
using System;
using Cysharp.Threading.Tasks;
using Spine.Unity;
using UnityEngine;
using UnityEngine.UI;
@@ -22,10 +21,9 @@
    // 创建坐骑 :id为0空坐骑也有配置
    //_skinID 坐骑的皮肤ID
    public async UniTask Create(int _skinID, int _heroSkinID = 0, float scale = 1f, Action _onComplete = null, string motionName = "idle")
    public void Create(int _skinID, int _heroSkinID = 0, float scale = 1f, Action _onComplete = null, string motionName = "idle")
    {
        pool = GameObjectPoolManager.Instance.GetPool(await UILoader.LoadPrefabAsync("UIHorse"));
        if (this == null) return;
        pool = GameObjectPoolManager.Instance.GetPool(UILoader.LoadPrefab("UIHorse"));
        if (instanceGO == null)
        {
            instanceGO = pool.Request();
@@ -45,7 +43,7 @@
            {
                skeletonGraphic.enabled = false;
            }
            await CreateHero(_heroSkinID, scale);
            CreateHero(_heroSkinID, scale);
            //避免重复创建
            return;
        }
@@ -68,12 +66,11 @@
            //卸下坐骑的情况
            skeletonGraphic.enabled = false;
            spineAnimationState = null;
        await CreateHero(_heroSkinID, scale);
            CreateHero(_heroSkinID, scale);
            return;
        }
        skeletonGraphic.skeletonDataAsset = await ResManager.Instance.LoadAssetAsync<SkeletonDataAsset>("UIEffect/Spine/Horse", skinConfig.Spine);
        if (this == null) return;
        skeletonGraphic.skeletonDataAsset = ResManager.Instance.LoadAsset<SkeletonDataAsset>("UIEffect/Spine/Horse", skinConfig.Spine);
        if (skeletonGraphic.skeletonDataAsset == null)
        {
@@ -86,6 +83,7 @@
            return;
        }
        skeletonGraphic.enabled = true;
        skeletonGraphic.MeshGenerator.settings.pmaVertexColors = skinConfig.pmaVertexColorsOpen == 1;
        skeletonGraphic.Initialize(true);
        skeletonGraphic.transform.localPosition = new Vector3(skinConfig.Poses[0], skinConfig.Poses[1], 0);
@@ -95,13 +93,12 @@
        if (motionName == "")
            motionName = GetFistSpineAnim();
        PlayAnimation(motionName, true);
        await CreateHero(_heroSkinID, scale);
        if (this == null) return;
        CreateHero(_heroSkinID, scale);
        spineAnimationState.Complete -= OnAnimationComplete;
        spineAnimationState.Complete += OnAnimationComplete;
    }
    public async UniTask CreateHero(int heroSkinID, float _scale)
    public void CreateHero(int heroSkinID, float _scale)
    {
        if (instanceGO == null)
        {
@@ -110,15 +107,15 @@
        // if (heroSkinID == 0)
        // {
        //     if (hero != null && hero.gameObject.activeSelf)
        //     {
        //         hero.SetActive(false);
        //     }
        //     {
        //         hero.SetActive(false);
        //     }
        //     return;    
        // }
        hero = instanceGO.GetComponentInChildren<UIHeroController>(true);
        if (hero == null)
        {
            return;
            return;
        }
        if (heroSkinID == 0)
        {
@@ -126,9 +123,8 @@
            return;
        }
        hero.SetActive(true);
        await hero.Create(heroSkinID, _scale);
        if (this == null) return;
        hero.Create(heroSkinID, _scale);
        // 确保 BoneFollowerGraphic 引用到正确的坐骑 SkeletonGraphic
        var boneFollower = hero.GetComponent<BoneFollowerGraphic>();
        if (boneFollower != null && skeletonGraphic != null && skeletonGraphic.enabled)
@@ -146,7 +142,7 @@
            boneFollower.enabled = false;
            hero.transform.localPosition = new Vector3(0, -50, 0);
        }
        if (isHeroShowBefore)
        {
            hero.transform.SetAsLastSibling();
@@ -163,7 +159,7 @@
            return;
        hero.PlayAnimation(motionName, loop, replay);
    }
    public UIHeroController GetHero()
    {
        return hero;
@@ -188,7 +184,7 @@
    /// <param name="motionName">动作名</param>
    /// <param name="loop">循环</param>
    /// <param name="replay">如果相同动作是否再次重播,比如跑步重播就会跳帧不顺滑</param>
    public virtual void PlayAnimation(string motionName, bool loop = false, bool replay=true)
    public virtual void PlayAnimation(string motionName, bool loop = false, bool replay = true)
    {
        if (spineAnimationState == null) return;
@@ -246,7 +242,7 @@
    }
    public void SetEnabled(bool isEnable)
    {
    {
        if (skeletonGraphic == null)
        {
            return;
Main/System/Horse/HorseSkinWin.cs
@@ -230,28 +230,16 @@
        var dict = HorseManager.Instance.GetAttrBySkinID(config);
        var attrList = new List<string>();
        var skinData = HorseManager.Instance.GetSkinData(config.SkinID);
        if (skinData != null)
        if (skinData != null && skinData.Star < config.StarMax)
        {
            //升星
            if (skinData.Star == 0 || skinData.Star >= config.StarMax)
            int i = 0;
            foreach (var kv in dict)
            {
                foreach (var kv in dict)
                {
                    attrList.Add(UIHelper.AppendColor(TextColType.itemchuanqi, PlayerPropertyConfig.GetFullDescription(kv.Key, kv.Value)));
                }
                return Language.Get("PhantasmPavilion07") + string.Join(Language.Get("L1112"), attrList);
                attrList.Add(UIHelper.AppendColor(TextColType.itemchuanqi, PlayerPropertyConfig.GetFullDescription(kv.Key, kv.Value)) +
                Language.Get("PhantasmPavilion12", UIHelper.AppendColor(TextColType.Green, "+" + PlayerPropertyConfig.GetValueDescription(kv.Key, config.AttrPerStarAddList[i]))));
                i++;
            }
            else
            {
                int i = 0;
                foreach (var kv in dict)
                {
                    attrList.Add(UIHelper.AppendColor(TextColType.itemchuanqi, PlayerPropertyConfig.GetFullDescription(kv.Key, kv.Value)) +
                    Language.Get("PhantasmPavilion12", UIHelper.AppendColor(TextColType.Green, "+" + PlayerPropertyConfig.GetValueDescription(kv.Key, config.AttrPerStarAddList[i]))));
                    i++;
                }
                return Language.Get("PhantasmPavilion07") + string.Join(Language.Get("L1112"), attrList);
            }
            return Language.Get("PhantasmPavilion07") + string.Join(Language.Get("L1112"), attrList);
        }
        else
        {
Main/System/Login/ServerData.cs
@@ -14,7 +14,7 @@
{
    public ServerGroup recommend;
    public ServerGroup[] common;
    public ServerGroup[] crossserver;
    public ServerGroup[] cross;
    public bool FindServerData(int _id, out ServerData _serverData)
    {
Main/System/Login/ServerListCenter.cs
@@ -168,11 +168,11 @@
        }
        //跨服服务器 不展示但是可以搜索用
        if (serverInfoCommon != null && serverInfoCommon.crossserver != null)
        if (serverInfoCommon != null && serverInfoCommon.cross != null)
        {
            for (int i = 0; i < serverInfoCommon.crossserver.Length; i++)
            for (int i = 0; i < serverInfoCommon.cross.Length; i++)
            {
                var group = serverInfoCommon.crossserver[i];
                var group = serverInfoCommon.cross[i];
                for (int j = 0; j < group.group_list.Length; j++)
                {
                    var serverData = group.group_list[j];
Main/System/Main/FightPowerManager.cs
@@ -550,18 +550,18 @@
        var Def = GetPropertyVaule(7, hero);
        var MaxHP = GetPropertyVaule(8, hero);
        var AtkSpeed = GetFighttPropertyVaule(11, hero);
        var StunRate = GetFighttPropertyVaule(21, hero);
        var StunRateDef = GetFighttPropertyVaule(22, hero);
        var SuperHitRate = GetFighttPropertyVaule(23, hero);
        var SuperHitRateDef = GetFighttPropertyVaule(24, hero);
        var ComboRate = GetFighttPropertyVaule(25, hero);
        var ComboRateDef = GetFighttPropertyVaule(26, hero);
        var MissRate = GetFighttPropertyVaule(27, hero);
        var MissRateDef = GetFighttPropertyVaule(28, hero);
        var ParryRate = GetFighttPropertyVaule(29, hero);
        var ParryRateDef = GetFighttPropertyVaule(30, hero);
        var SuckHPPer = GetFighttPropertyVaule(31, hero);
        var SuckHPPerDef = GetFighttPropertyVaule(32, hero);
        var StunRate = GetFighttPropertyVaule(21, hero) + GetFighttPropertyVaule(33, hero);
        var StunRateDef = GetFighttPropertyVaule(22, hero) + GetFighttPropertyVaule(34, hero);
        var SuperHitRate = GetFighttPropertyVaule(23, hero) + GetFighttPropertyVaule(33, hero);
        var SuperHitRateDef = GetFighttPropertyVaule(24, hero) + GetFighttPropertyVaule(34, hero);
        var ComboRate = GetFighttPropertyVaule(25, hero) + GetFighttPropertyVaule(33, hero);
        var ComboRateDef = GetFighttPropertyVaule(26, hero) + GetFighttPropertyVaule(34, hero);
        var MissRate = GetFighttPropertyVaule(27, hero) + GetFighttPropertyVaule(33, hero);
        var MissRateDef = GetFighttPropertyVaule(28, hero) + GetFighttPropertyVaule(34, hero);
        var ParryRate = GetFighttPropertyVaule(29, hero) + GetFighttPropertyVaule(33, hero);
        var ParryRateDef = GetFighttPropertyVaule(30, hero) + GetFighttPropertyVaule(34, hero);
        var SuckHPPer = GetFighttPropertyVaule(31, hero) + GetFighttPropertyVaule(33, hero);
        var SuckHPPerDef = GetFighttPropertyVaule(32, hero) + GetFighttPropertyVaule(34, hero);
        var FinalDamPer = GetFighttPropertyVaule(35, hero);
        var FinalDamPerDef = GetFighttPropertyVaule(36, hero);
@@ -836,6 +836,7 @@
    #endregion
    //和战力计算无关,重算属性展示用
    public Dictionary<int, long> GetHeroTotalAttr(HeroInfo hero)
    {
@@ -845,7 +846,11 @@
        var pConfig = PlayerPropertyConfig.GetValues();
        foreach (var config in pConfig)
        {
            if (config.showType < 1 || config.showType > 4)
            if (config.showType != 1 &&
                config.showType != 2 &&
                config.showType != 3 &&
                config.showType != 4 &&
                config.showType != 7)
            {
                continue;
            }
@@ -860,6 +865,18 @@
            }
        }
        //六大战斗属性需要再加上总的战斗属性
        int[] fightAttrList = { 21, 23, 25, 27, 29, 31};
        foreach (var attr in fightAttrList)
        {
            tmpAttrs[attr] += tmpAttrs[33];
        }
        int[] fightDefAttrList = { 22, 24, 26, 28, 30, 32};
        foreach (var attr in fightDefAttrList)
        {
            tmpAttrs[attr] += tmpAttrs[34];
        }
        return tmpAttrs;
    }
Main/System/Main/HomeWin.cs
@@ -74,6 +74,7 @@
    [SerializeField] TimeRushCell timeRushCell;
    [SerializeField] HeroDebutCell heroDebutCell;
    [SerializeField] HeroReturnCell heroReturnCell;
    [SerializeField] Button festivalActivityBtn;
    //坐骑
    [SerializeField] Image horseBGImg;
@@ -232,7 +233,10 @@
        {
            UIManager.Instance.OpenWindowAsync<DailySpecialsBaseWin>().Forget();
        });
        festivalActivityBtn.AddListener(() =>
        {
            UIManager.Instance.OpenWindow<FestivalActivityWin>();
        });
    }
@@ -298,6 +302,7 @@
        DisplayTimeRush();
        DisplayHeroDebut();
        DisplayHeroReturn();
        DisplayFestivalActivity();
        DelayPlayMusic().Forget();
    }
@@ -346,6 +351,10 @@
        {
            DisplayGalaBtn();
        }
        else if (type == OperationType.FestivalActivity)
        {
            DisplayFestivalActivity();
        }
    }
    private void OpenServerActivityStateChange()
@@ -354,6 +363,7 @@
        DisplayHeroDebut();
        DisplayHeroReturn();
        DisplayGalaBtn();
        DisplayFestivalActivity();
    }
    private void OnShowGiftIdListAddEvent()
@@ -876,6 +886,10 @@
        {
            DisplayHeroReturn();
        }
        else if (funcId == (int)FuncOpenEnum.FestivalActivity)
        {
            DisplayFestivalActivity();
        }
    }
    private void OnUpdateFirstChargeInfo()
@@ -946,8 +960,7 @@
    void DisplayGalaBtn()
    {
        bool isGalaOpen = TotDayRechargeManager.Instance.IsOpen || TotalRechargeManager.Instance.IsOpen;
        osGalaBtn.SetActive(OSActivityManager.Instance.IsOpenedOSGala() || isGalaOpen);
        osGalaBtn.SetActive(OSActivityManager.Instance.IsOpenedOSGala());
    }
    void DisplayTimeRush()
@@ -976,6 +989,12 @@
            return;
        heroReturnCell.Display();
    }
    void DisplayFestivalActivity()
    {
        bool isOpen = FestivalActivityManager.Instance.IsFestivalActivityOpen();
        festivalActivityBtn.SetActive(isOpen);
    }
}
Main/System/OSActivity/OSActivityManager.cs
@@ -372,6 +372,12 @@
        {
            return false;
        }
        if (TotDayRechargeManager.Instance.IsOpen || TotalRechargeManager.Instance.IsOpen)
        {
            return true;
        }
        if (needLastDay)
        {
            //结束后延迟一天关闭展示
Main/System/OpenServerActivity/OperationTimeHepler.cs
@@ -497,72 +497,190 @@
    public void UpdateActTotalRechargeInfo(HAA1D_tagSCActTotalRechargeInfo package)
    {
        OperationBase operationBase = null;
        operationDict.TryGetValue(OperationType.TotalRecharge, out operationBase);
        var opreationType = OperationType.TotalRecharge;
        switch (package.ActNum)
        {
            case 10:
                opreationType = OperationType.TotalRecharge;
                break;
            case 30:
                opreationType = OperationType.FestivalActivity_RechargeTotal;
                break;
        }
        if (string.IsNullOrEmpty(package.StartDate) || string.IsNullOrEmpty(package.EndtDate))
        {
            ForceStopOperation(OperationType.TotalRecharge);
            ForceStopOperation(opreationType);
            return;
        }
        else
        {
            if (operationBase == null)
            {
                operationBase = new OperationTotalRechargeInfo();
                operationDict.Add(OperationType.TotalRecharge, operationBase);
            }
            OperationTotalRechargeInfo operation = operationBase as OperationTotalRechargeInfo;
            operation.Reset();
            operation.startDate = ParseOperationDate(package.StartDate);
            operation.endDate = ParseOperationDate(package.EndtDate);
            operation.ActNum = package.ActNum;
            operation.CfgID = package.CfgID;
            var config = ActTotalRechargeConfig.Get(package.CfgID);
            if (config == null)
            {
                SysNotifyMgr.Instance.ShowTip("LoadConfigErr");
                return;
            }
            if (operationTimeUpdateEvent != null)
            {
                operationTimeUpdateEvent(OperationType.TotalRecharge);
            }
        if (!operationDict.TryGetValue(opreationType, out OperationBase operationBase))
        {
            operationBase = new OperationTotalRechargeInfo();
            operationDict.Add(opreationType, operationBase);
        }
        OperationTotalRechargeInfo operation = operationBase as OperationTotalRechargeInfo;
        operation.Reset();
        operation.startDate = ParseOperationDate(package.StartDate);
        operation.endDate = ParseOperationDate(package.EndtDate);
        operation.ActNum = package.ActNum;
        operation.CfgID = package.CfgID;
        var config = ActTotalRechargeConfig.Get(package.CfgID);
        if (config == null)
        {
            SysNotifyMgr.Instance.ShowTip("LoadConfigErr");
            return;
        }
        operation.dayReset = config.IsDayReset == 1;
        operationTimeUpdateEvent?.Invoke(opreationType);
    }
    public void UpdateActTotDayRechargeInfo(HAA1B_tagSCActTotDayRechargeInfo package)
    {
        OperationBase operationBase = null;
        operationDict.TryGetValue(OperationType.TotDayRecharge, out operationBase);
        var opreationType = OperationType.TotDayRecharge;
        switch (package.ActNum)
        {
            case 10:
                opreationType = OperationType.TotDayRecharge;
                break;
            case 30:
                opreationType = OperationType.FestivalActivity_RechargeTotDay;
                break;
        }
        if (string.IsNullOrEmpty(package.StartDate) || string.IsNullOrEmpty(package.EndtDate))
        {
            ForceStopOperation(OperationType.TotDayRecharge);
            ForceStopOperation(opreationType);
            return;
        }
        else
        if (!operationDict.TryGetValue(opreationType, out OperationBase operationBase))
        {
            if (operationBase == null)
            {
                operationBase = new OperationTotDayRechargeInfo();
                operationDict.Add(OperationType.TotDayRecharge, operationBase);
            }
            OperationTotDayRechargeInfo operation = operationBase as OperationTotDayRechargeInfo;
            operation.Reset();
            operation.startDate = ParseOperationDate(package.StartDate);
            operation.endDate = ParseOperationDate(package.EndtDate);
            operation.ActNum = package.ActNum;
            operation.CfgID = package.CfgID;
            var config = ActTotalRechargeConfig.Get(package.CfgID);
            if (config == null)
            {
                SysNotifyMgr.Instance.ShowTip("LoadConfigErr");
                return;
            }
            operation.dayReset = config.IsDayReset == 1;
            operationTimeUpdateEvent?.Invoke(OperationType.TotDayRecharge);
            operationBase = new OperationTotDayRechargeInfo();
            operationDict.Add(opreationType, operationBase);
        }
        OperationTotDayRechargeInfo operation = operationBase as OperationTotDayRechargeInfo;
        operation.Reset();
        operation.startDate = ParseOperationDate(package.StartDate);
        operation.endDate = ParseOperationDate(package.EndtDate);
        operation.ActNum = package.ActNum;
        operation.CfgID = package.CfgID;
        if (ActTotDayRechargeConfig.Get(package.CfgID) == null)
        {
            SysNotifyMgr.Instance.ShowTip("LoadConfigErr");
            return;
        }
        operationTimeUpdateEvent?.Invoke(opreationType);
    }
    public void UpdateFlashSaleActivityInfo(HAA10_tagSCActSpecialSaleInfo package)
    {
        var opreationType = OperationType.FestivalActivity;
        switch (package.ActNum)
        {
            case 30:
                opreationType = OperationType.FestivalActivity;
                break;
        }
        if (string.IsNullOrEmpty(package.StartDate) || string.IsNullOrEmpty(package.EndtDate))
        {
            ForceStopOperation(opreationType);
            return;
        }
        if (!operationDict.TryGetValue(opreationType, out OperationBase operationBase))
        {
            operationBase = new OperationFlashSaleActivityInfo();
            operationDict.Add(opreationType, operationBase);
        }
        OperationFlashSaleActivityInfo operation = operationBase as OperationFlashSaleActivityInfo;
        operation.Reset();
        operation.startDate = ParseOperationDate(package.StartDate);
        operation.endDate = ParseOperationDate(package.EndtDate);
        operation.ActNum = package.ActNum;
        operation.CfgID = package.CfgID;
        if (ActSpecialSaleConfig.Get(package.CfgID) == null)
        {
            SysNotifyMgr.Instance.ShowTip("LoadConfigErr");
            return;
        }
        operationTimeUpdateEvent?.Invoke(opreationType);
    }
    public void UpdateCheckInActivityInfo(HAA23_tagSCActSignInfo package)
    {
        var opreationType = OperationType.FestivalActivity_CheckIn;
        switch (package.ActNum)
        {
            case 30:
                opreationType = OperationType.FestivalActivity_CheckIn;
                break;
        }
        if (string.IsNullOrEmpty(package.StartDate) || string.IsNullOrEmpty(package.EndtDate))
        {
            ForceStopOperation(opreationType);
            return;
        }
        if (!operationDict.TryGetValue(opreationType, out OperationBase operationBase))
        {
            operationBase = new OperationCheckInActivityInfo();
            operationDict.Add(opreationType, operationBase);
        }
        OperationCheckInActivityInfo operation = operationBase as OperationCheckInActivityInfo;
        operation.Reset();
        operation.startDate = ParseOperationDate(package.StartDate);
        operation.endDate = ParseOperationDate(package.EndtDate);
        operation.ActType = package.ActNum;
        operation.CfgID = package.CfgID;
        if (ActSignConfig.Get(package.CfgID) == null)
        {
            SysNotifyMgr.Instance.ShowTip("LoadConfigErr");
            return;
        }
        operationTimeUpdateEvent?.Invoke(opreationType);
    }
    public void UpdateMissionActivityInfo(HAA71_tagSCActTaskInfo package)
    {
        var opreationType = OperationType.FestivalActivity_Mission;
        switch (package.ActNum)
        {
            case 30:
                opreationType = OperationType.FestivalActivity_Mission;
                break;
        }
        if (string.IsNullOrEmpty(package.StartDate) || string.IsNullOrEmpty(package.EndtDate))
        {
            ForceStopOperation(opreationType);
            return;
        }
        if (!operationDict.TryGetValue(opreationType, out OperationBase operationBase))
        {
            operationBase = new OperationMissionActivityInfo();
            operationDict.Add(opreationType, operationBase);
        }
        OperationMissionActivityInfo operation = operationBase as OperationMissionActivityInfo;
        operation.Reset();
        operation.startDate = ParseOperationDate(package.StartDate);
        operation.endDate = ParseOperationDate(package.EndtDate);
        operation.ActType = package.ActNum;
        operation.CfgID = package.CfgID;
        var config = ActTaskConfig.Get(package.CfgID);
        if (config == null)
        {
            SysNotifyMgr.Instance.ShowTip("LoadConfigErr");
            return;
        }
        operation.dayReset = config.IsDayReset == 1;
        operationTimeUpdateEvent?.Invoke(opreationType);
    }
    // public void UpdateActYunShiInfo(HAA87_tagMCActYunshiInfo package)
@@ -1157,5 +1275,10 @@
    HeroReturn = 3, //日期型活动 - 武将返场
    TotalRecharge = 4,//累充活动
    TotDayRecharge = 5, //累充天活动
    FestivalActivity = 6,   //节日活动
    FestivalActivity_RechargeTotDay = 7,   //节日活动-累天充值
    FestivalActivity_RechargeTotal = 8,   //节日活动-累充值
    FestivalActivity_CheckIn = 9,   //节日活动-签到
    FestivalActivity_Mission = 10,   //节日活动-任务
    max,
}
Main/System/OtherPlayerDetail/OtherPlayerDetailManager.cs
@@ -32,6 +32,10 @@
        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEventOnRelogin -= OnBeforePlayerDataInitializeEventOnRelogin;
    }
    public bool IsRobot(int playerID)
    {
        return RobotConfig.HasKey(playerID);
    }
    public void OnBeforePlayerDataInitializeEventOnRelogin()
    {
Main/System/OtherPlayerDetail/OtherPlayerDetailWin.cs
@@ -136,7 +136,7 @@
    private void DisplayMingge(int playerID)
    {
        var mingge = manager.GetMinggeTotalData(playerID);
        txtMinggeLv.text = Language.Get("OtherPlayerDetail13", mingge == null ? 0 : mingge.GWLV);
        txtMinggeLv.text = Language.Get("OtherPlayerDetail17", mingge == null ? 0 : mingge.GWLV);
    }
    private void DisplayGuildInfo(OtherPlayerDetailManager.ViewPlayerData viewPlayerData)
@@ -156,7 +156,10 @@
    {
        txtPlayerName.text = viewPlayerData.PlayerName;
        txtPlayerId.text = Language.Get("OtherPlayerDetail02", viewPlayerData.PlayerID);
        txtServerName.text = Language.Get("PlayerProfile11", ServerListCenter.Instance.GetServerName(viewPlayerData.ServerID));
        if (OtherPlayerDetailManager.Instance.IsRobot(viewPlayerData.PlayerID))
            txtServerName.text = Language.Get("PlayerProfile11", ServerListCenter.Instance.GetServerName(UIHelper.GetServerIDByAccount(PlayerDatas.Instance.baseData.AccID)));
        else
            txtServerName.text = Language.Get("PlayerProfile11", ServerListCenter.Instance.GetServerName(viewPlayerData.ServerID));
        txtLV.text = viewPlayerData.LV.ToString();
        avatarCell.InitUI(AvatarHelper.GetAvatarModel(viewPlayerData.PlayerID, viewPlayerData.Face, viewPlayerData.FacePic)).Forget();
        officialTitle.InitUI(viewPlayerData.RealmLV, viewPlayerData.TitleID, 0.65f).Forget();
Main/System/PhantasmPavilion/AvatarHelper.cs
@@ -78,7 +78,7 @@
    public static int GetAvatarBgColor(int faceID)
    {
        int defaultColor = 1;
        int defaultColor = 0;
        if (!PlayerFaceConfig.HasKey(faceID))
            return defaultColor;
        return PlayerFaceConfig.Get(faceID).BgColor;
Main/System/PhantasmPavilion/PhantasmPavilionManager.DefaultID.cs
@@ -139,7 +139,7 @@
    public int GetModelBgColor(int id)
    {
        int defaultColor = 1;
        int defaultColor = 0;
        if (!ModelConfig.HasKey(id))
            return defaultColor;
        return ModelConfig.Get(id).ModelBgColor;
Main/System/PhantasmPavilion/PhantasmPavilionManager.cs
@@ -215,7 +215,7 @@
        int unlockValue = GetUnlockValue(type, id);
        int resourceType = GetResourceType(type, id);
        string resourceValue = GetResourceValue(type, id);
        if ((UnlockWay == 3 || UnlockWay == 4) && resourceValue == "")
        if ((UnlockWay == 3 || UnlockWay == 4 || UnlockWay == 5) && resourceValue == "")
        {
            int skinID = 0;
            if (UnlockWay == 3)
@@ -227,6 +227,12 @@
            else if (UnlockWay == 4)
            {
                skinID = unlockValue; // UnlockValue 直接就是 skinID
            }
            else if (UnlockWay == 5)
            {
                int modelID = unlockValue; // UnlockValue 是 ModelID
                if (!ModelConfig.HasKey(modelID)) return;
                skinID = ModelConfig.Get(modelID).SkinID; // 拿到形象对应的皮肤ID
            }
            if (!HeroSkinConfig.HasKey(skinID)) return;
@@ -552,90 +558,49 @@
    // 除道具解锁外,其他方式暂默认永久
    // 1 - 默认解锁,即创角就可用的
    // 2 - 道具解锁,支持时效、升级, Value配物品ID
    // 3 - 关联武将解锁,Value配武将ID
    public bool IsUnlock(PhantasmPavilionType type, int id)
    {
        // 配置表中不存在,视为未解锁
        if (!Has(type, id))
            return false;
        if (!Has(type, id)) return false;
        int unlockWayValue = GetUnlockWay(type, id);
        int unlockValue = GetUnlockValue(type, id);
        // 解锁方式无效
        if (!Enum.IsDefined(typeof(PhantasmPavilionUnlockWay), unlockWayValue))
            return false;
        var unlockWay = (PhantasmPavilionUnlockWay)unlockWayValue;
        switch (unlockWay)
        if (unlockWayValue == 1) return true; // 1 - 默认解锁
        if (unlockWayValue == 2) // 2 - 道具解锁
        {
            case PhantasmPavilionUnlockWay.Activate:
                return true;
            case PhantasmPavilionUnlockWay.Hero:
                bool hasHero = HeroManager.Instance.HasHero(unlockValue);
                return hasHero;
            case PhantasmPavilionUnlockWay.Item:
                // 封包里没有
                if (!TryGetInfo(type, id, out var info))
                    return false;
                // 玩家数据中的状态是“未激活”
                if (!info.State)
                    return false;
                // 是否为“已过期的道具”
                if (IsExpired(info, unlockWay))
                    return false;
                return true;
            case PhantasmPavilionUnlockWay.Skin:
                bool hasSkin = HeroUIManager.Instance.IsHeroSkinActive(HeroConfig.GetHeroIDBySkinID(unlockValue), unlockValue);
                return hasSkin;
            default:
                return false;
            if (!TryGetInfo(type, id, out var info)) return false;
            if (!info.State) return false;
            if (IsExpired(info, PhantasmPavilionUnlockWay.Item)) return false;
            return true;
        }
        // 3、4、5及以上全部交给分发函数按表格类型独立处理
        return CheckTableSpecificUnlock(type, unlockWayValue, unlockValue);
    }
    /// <summary>
    /// 获得当前状态
    /// </summary>
    /// <returns>0 - 未激活, 1 - 可激活, 2 - 已激活</returns>
    public PhantasmPavilionState GetUnLockState(PhantasmPavilionType type, int id)
    {
        // 配置表中不存在,视为“未激活”
        if (!Has(type, id))
            return PhantasmPavilionState.Locked;
        if (!Has(type, id)) return PhantasmPavilionState.Locked;
        // 已经解锁
        if (IsUnlock(type, id))
            return PhantasmPavilionState.Activated;
        // 如果已经满足解锁条件,直接返回 Activated
        if (IsUnlock(type, id)) return PhantasmPavilionState.Activated;
        // 运行到这里,说明物品是“未激活”或“已过期”状态 (IsUnlock 返回 false)
        // 无效的解锁方式
        int unlockWayValue = GetUnlockWay(type, id);
        if (!Enum.IsDefined(typeof(PhantasmPavilionUnlockWay), unlockWayValue))
            return PhantasmPavilionState.Locked;
        var unlockWay = (PhantasmPavilionUnlockWay)unlockWayValue;
        int unlockValue = GetUnlockValue(type, id);
        switch (unlockWay)
        // 只有道具解锁(2)存在"未激活但材料足够"的特有中间状态
        if (unlockWayValue == 2)
        {
            // 检查道具激活条件
            case PhantasmPavilionUnlockWay.Item:
                return CheckCanActivateByItem(type, id, unlockValue)
                    ? PhantasmPavilionState.CanActivate
                    : PhantasmPavilionState.Locked;
            // 检查武将激活条件
            case PhantasmPavilionUnlockWay.Hero:
                int heroID = unlockValue;
                return HeroManager.Instance.HasHero(heroID)
                    ? PhantasmPavilionState.Activated
                    : PhantasmPavilionState.Locked;
            case PhantasmPavilionUnlockWay.Skin:
                return HeroUIManager.Instance.IsHeroSkinActive(HeroConfig.GetHeroIDBySkinID(unlockValue), unlockValue)
                    ? PhantasmPavilionState.Activated
                    : PhantasmPavilionState.Locked;
            default:
                return PhantasmPavilionState.Locked;
            return CheckCanActivateByItem(type, id, unlockValue)
                ? PhantasmPavilionState.CanActivate
                : PhantasmPavilionState.Locked;
        }
        // 其他关联解锁如果不满足 IsUnlock,则必定是 Locked 状态
        return PhantasmPavilionState.Locked;
    }
    // 检查是否满足“通过道具激活”的条件
    private bool CheckCanActivateByItem(PhantasmPavilionType type, int id, int itemId)
@@ -659,6 +624,31 @@
        return true;
    }
    /// <summary>
    /// 根据所属表格(Type)解析 UnlockWay 的特定含义并判断是否满足条件 (排除 UnlockWay 1 和 2)
    /// </summary>
    public bool CheckTableSpecificUnlock(PhantasmPavilionType type, int unlockWay, int unlockValue)
    {
        switch (type)
        {
            case PhantasmPavilionType.Face:
                // 头像表独有的 UnlockWay 解析规则
                if (unlockWay == 3) return HeroManager.Instance.HasHero(unlockValue);
                if (unlockWay == 4) return HeroUIManager.Instance.IsHeroSkinActive(HeroConfig.GetHeroIDBySkinID(unlockValue), unlockValue);
                if (unlockWay == 5) return IsUnlock(PhantasmPavilionType.Model, unlockValue); // 关联形象
                break;
            case PhantasmPavilionType.FacePic:
            case PhantasmPavilionType.ChatBox:
            case PhantasmPavilionType.Title:
            case PhantasmPavilionType.Model:
                // 其他表目前的共有解析规则
                if (unlockWay == 3) return HeroManager.Instance.HasHero(unlockValue);
                if (unlockWay == 4) return HeroUIManager.Instance.IsHeroSkinActive(HeroConfig.GetHeroIDBySkinID(unlockValue), unlockValue);
                break;
        }
        return false;
    }
    public void CheckTimeOut()
    {
        bool isTimeOut = false;
@@ -977,7 +967,9 @@
    Activate = 1,               // 默认(创角色就可以用的)
    Item,                       // 道具
    Hero,                       // 武将
    Skin,                   // 皮肤
    Skin,                       // 皮肤
    Model,                      // 形象
}
/// 幻境阁物品的状态
Main/System/PhantasmPavilion/PhantasmPavilionUnlockButton.cs
@@ -24,31 +24,24 @@
                int useCnt = manager.GetUnlockNeedCnt(type, id);
                if (useCnt > hasCnt)
                {
                    if (!ItemConfig.HasKey(unlockValue))
                        return;
                    if (!ItemConfig.HasKey(unlockValue)) return;
                    string name = ItemConfig.Get(unlockValue).ItemName;
                    SysNotifyMgr.Instance.ShowTip("UnLockFail2", name);
                    return;
                }
            }
            else if (unlockWay == 3)
            else if (unlockWay != 1) // 统一处理 3, 4, 5 以及未来自定义的类型
            {
                bool hasHero = HeroManager.Instance.HasHero(unlockValue);
                if (!hasHero)
                // UI 层不再硬编码含义,直接调用基于 Type 的校验
                bool canUnlock = manager.CheckTableSpecificUnlock(type, unlockWay, unlockValue);
                if (!canUnlock)
                {
                    SysNotifyMgr.Instance.ShowTip("UnLockFail1");
                    // 这里统一复用 UnLockFail1,或未来在 CheckTableSpecificUnlock 中返回更具体的错误枚举
                    SysNotifyMgr.Instance.ShowTip("UnLockFail1");
                    return;
                }
            }
            else if (unlockWay == 4) // 新增:如果是皮肤解锁
            {
                bool hasSkin = HeroUIManager.Instance.IsHeroSkinActive(HeroConfig.GetHeroIDBySkinID(unlockValue), unlockValue);
                if (!hasSkin)
                {
                    SysNotifyMgr.Instance.ShowTip("UnLockFail1");
                    return;
                }
            }
            manager.SendOPPack(type, PhantasmPavilionOperation.Activate, (uint)id);
            SysNotifyMgr.Instance.ShowTip("UnLockSuccess");
        });
Main/System/Qunying/QYBattleFailWin.cs
@@ -85,7 +85,7 @@
        enemyAvatarCell.InitUI(AvatarHelper.GetAvatarModel((int)tagPlayerID, (int)enemyFace, (int)enemyFacePic)).Forget();
        enemyAvatarCell.SetListener(() =>
        {
            AvatarHelper.TryViewOtherPlayerInfo((int)tagPlayerID, viewPlayerLineupType: (int)BattlePreSetType.Qunying);
            AvatarHelper.TryViewOtherPlayerInfo((int)tagPlayerID, (int)info.ServerID, viewPlayerLineupType: (int)BattlePreSetType.Qunying);
        });
        txtMyName.text = PlayerDatas.Instance.baseData.PlayerName;
Main/System/Qunying/QYBattleVictoryWin.cs
@@ -75,7 +75,7 @@
        enemyAvatarCell.InitUI(AvatarHelper.GetAvatarModel((int)tagPlayerID, (int)enemyFace, (int)enemyFacePic)).Forget();
        enemyAvatarCell.SetListener(() =>
        {
            AvatarHelper.TryViewOtherPlayerInfo((int)tagPlayerID, viewPlayerLineupType: (int)BattlePreSetType.Qunying);
            AvatarHelper.TryViewOtherPlayerInfo((int)tagPlayerID, (int)info.ServerID, viewPlayerLineupType: (int)BattlePreSetType.Qunying);
        });
        txtMyName.text = PlayerDatas.Instance.baseData.PlayerName;
Main/System/Qunying/QYBattleWin.cs
@@ -213,7 +213,7 @@
        enemyAvatarCell.InitUI(AvatarHelper.GetAvatarModel((int)info.PlayerID, (int)info.Face, (int)info.FacePic)).Forget();
        enemyAvatarCell.SetListener(() =>
        {
            AvatarHelper.TryViewOtherPlayerInfo((int)info.PlayerID, viewPlayerLineupType: (int)BattlePreSetType.Qunying);
            AvatarHelper.TryViewOtherPlayerInfo((int)info.PlayerID, (int)info.ServerID, viewPlayerLineupType: (int)BattlePreSetType.Qunying);
        });
        var team = GetTeamHeroList(enemyTeam);
        enemyCountry.RefreshOnTeamCountry(team, true);
Main/System/Qunying/QYFighterCell.cs
@@ -31,6 +31,12 @@
        {
            if (matchInfo == null)
                return;
            if (QunyingManager.Instance.IsCrossGrouping())
            {
                SysNotifyMgr.Instance.ShowTip("QYCrossFightError");
                return;
            }
            if (!UIHelper.CheckMoneyCount(QunyingManager.challengeMoneyType, 1, 1))
            {
                StoreModel.Instance.ShowBuyItem(QunyingManager.challengeShopID, -1);
@@ -44,13 +50,19 @@
        queryPlayerBtn.AddListener(() =>
        {
            if (GeneralDefine.IsRobot((int)matchInfo.PlayerID)) return;
            AvatarHelper.TryViewOtherPlayerInfo((int)matchInfo.PlayerID, viewPlayerLineupType: (int)BattlePreSetType.Qunying);
            AvatarHelper.TryViewOtherPlayerInfo((int)matchInfo.PlayerID, (int)matchInfo.ServerID, viewPlayerLineupType: (int)BattlePreSetType.Qunying);
        });
        quickChallengeBtn.AddListener(() =>
        {
            if (matchInfo == null)
                return;
            if (QunyingManager.Instance.IsCrossGrouping())
            {
                SysNotifyMgr.Instance.ShowTip("QYCrossFightError");
                return;
            }
            if (!UIHelper.CheckMoneyCount(QunyingManager.challengeMoneyType, 1, 1))
            {
                StoreModel.Instance.ShowBuyItem(QunyingManager.challengeShopID, -1);
@@ -64,7 +76,12 @@
        {
            if (matchInfo == null)
                return;
            if (QunyingManager.Instance.IsCrossGrouping())
            {
                SysNotifyMgr.Instance.ShowTip("QYCrossFightError");
                return;
            }
            //最低显示两次,但可以最低挑战1次
            var cnt = Math.Max(1, Math.Min(5, UIHelper.GetMoneyCnt(QunyingManager.challengeMoneyType)));
            if (!UIHelper.CheckMoneyCount(QunyingManager.challengeMoneyType, cnt, 1))
Main/System/Qunying/QYNoteCell.cs
@@ -52,7 +52,7 @@
        tagAvatarCell.SetListener(() =>
        {
            if (GeneralDefine.IsRobot((int)arenaGameRec.Value3)) return;
            AvatarHelper.TryViewOtherPlayerInfo((int)arenaGameRec.Value3, viewPlayerLineupType: (int)BattlePreSetType.Arena);
            AvatarHelper.TryViewOtherPlayerInfo((int)arenaGameRec.Value3, (int)arenaGameRec.Value1, viewPlayerLineupType: (int)BattlePreSetType.Arena);
        });
        tagLVTxt.text = arenaGameRec.Value8.ToString();
        tagNameTxt.text = arenaGameRec.Name;
Main/System/Qunying/QYPlayerTop3Cell.cs
@@ -40,7 +40,7 @@
        queryPlayerBtn.SetListener(() =>
        {
            if (GeneralDefine.IsRobot((int)rankData.id)) return;
            AvatarHelper.TryViewOtherPlayerInfo((int)rankData.id, viewPlayerLineupType: (int)BattlePreSetType.Qunying);
            AvatarHelper.TryViewOtherPlayerInfo((int)rankData.id, UIHelper.GetServerIDByAccount(rankData.name2), viewPlayerLineupType: (int)BattlePreSetType.Qunying);
        });
        fightPowerText.text = UIHelper.ReplaceLargeArtNum(rankData.fightPower);
    }
Main/System/Qunying/QYWin.cs
@@ -171,8 +171,7 @@
    //活动时间
    void ShowGameTime()
    {
        var zoneInfo = CrossServerBaseManager.Instance.GetCrossZoneInfo(QunyingManager.DataMapID);
        if (zoneInfo != null && zoneInfo.ZoneID == 0)
        if (QunyingManager.Instance.IsCrossGrouping())
        {
            //倒计时按0:05结束
            var seconds = (TimeUtility.GetTodayStartTime().AddMinutes(5) - TimeUtility.GetCommServerNow(0)).TotalSeconds;
Main/System/Qunying/QunyingManager.cs
@@ -380,6 +380,17 @@
        return true;
    }
    public bool IsCrossGrouping()
    {
        var zoneInfo = CrossServerBaseManager.Instance.GetCrossZoneInfo(DataMapID);
        if (zoneInfo != null && zoneInfo.ZoneID == 0)
        {
            return true;
        }
        return false;
    }
    #region 红点
    public Redpoint parentRedpoint = new Redpoint(MainRedDot.Qunying);
Main/System/Redpoint/MainRedDot.cs
@@ -155,7 +155,8 @@
    public const int RedPoint_OSHeroTrain = 481;
    public const int RedPoint_OSBeautyMM = 482;
    public const int RedPoint_OSMingge = 483;
    public const int HeroReturnRepoint = 484; //武将返场
    public const int HeroReturnRepoint = 484;   //武将返场
    public const int FestivalActivityRepoint = 485;    //节日活动
    public void Register()
    {
Main/System/Settlement/BattleSettlementManager.cs
@@ -260,9 +260,10 @@
    public void RequestTurnFightData(string guid, string date, int mapID, int crossServerID = 0)
    {
        //mobile.secondworld.net.cn:53080\S9006\20251202\3042602\5b11338f-cf2c-11f0-a0a0-000c29b22418.tfr
        var serverID = crossServerID !=0 ? crossServerID : UIHelper.GetServerIDByAccount(PlayerDatas.Instance.baseData.AccID);
        // crossServerID 只是为了取区服信息,后续的使用依然用serverID做逻辑
        var serverID = UIHelper.GetServerIDByAccount(PlayerDatas.Instance.baseData.AccID);
        var url = ServerListCenter.Instance.GetServerUrl(serverID);
        var url = ServerListCenter.Instance.GetServerUrl(crossServerID !=0 ? crossServerID : serverID);
        string assetVersionUrl = string.Empty;
        if (string.IsNullOrEmpty(date))
Main/Utility/EnumHelper.cs
@@ -859,6 +859,7 @@
    Qunying = 62, //群英榜
    HeroDebut = 63,//武将登场
    HeroReturn = 64,  //武将返场
    FestivalActivity = 65,//节日活动
}
@@ -1815,8 +1816,13 @@
    TimeRushAct = 200,  //轮回殿(武将冲刺)
    HeroDebutAct = 201,  //英雄登场活动
    HeroReturnAct = 202,  //英雄返场活动
    TotalRechargeAct = 4,   //累充活动
    TotDayRechargeAct = 5,  //累充天活动
    TotalRechargeAct = 203,   //累充活动
    TotDayRechargeAct = 204,  //累充天活动
    FestivalActivityAct = 205,  //节日活动
    FestivalActivityRechargeTotalAct = 206,
    FestivalActivityRechargeTotDayAct = 207,
    FestivalActivityCheckInAct = 208,
    FestivalActivityMissionAct = 209,   //节日活动-任务
}
//仙玉购买的二次确认框类型
Main/Utility/UIHelper.cs
@@ -23,10 +23,16 @@
    //不需要提取翻译的文本
    private static readonly string[] numbers = new string[] { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九" };
    private static readonly string[] units = new string[] { "十", "百", "千", "万" };
    private static readonly string[] unitFTs = new string[] { "十", "百", "千", "萬" };
    //数字转中文(只做小数字),海外版本调用改函数切换版本请直接返回数字
    public static string ChineseNumber(int number)
    {
        string langId = Language.Id;
        if (!string.IsNullOrEmpty(langId) && langId != "zh" && langId != "ft")
            return number.ToString();
        string[] curUnits = (langId == "ft") ? unitFTs : units;
        if (number == 0)
            return numbers[0];
@@ -42,7 +48,7 @@
                if (needZero)
                    result = StringUtility.Concat(numbers[0] + result);
                result = numbers[part] + (unitPlace == 1 ? "" : units[unitPlace - 2]) + result; // 单位只在十、百、千、万内部使用
                result = numbers[part] + (unitPlace == 1 ? "" : curUnits[unitPlace - 2]) + result; // 单位只在十、百、千、万内部使用
                needZero = false;
            }
            else
@@ -567,7 +573,7 @@
            case 43:
            case 44:
                return GetUIColor(TextColType.itemshenhua, bright);
        }