yyl
6 天以前 89ef46a926d5b7a05cf4c0b35d4849395667f90a
WEBGL跟安卓混合开发 资源加载异步
18个文件已修改
651 ■■■■■ 已修改文件
Main/Config/ConfigManager.cs 463 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/Socket/ClientSocket.cs 70 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Arena/ArenaBattleFailWin.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Arena/ArenaBattleVictoryWin.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Arena/ArenaChallengeCell.cs 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Arena/ArenaPlayerRankCell.cs 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Arena/ArenaPlayerTop3Cell.cs 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Arena/ArenaRecordCell.cs 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Arena/ArenaWin.cs 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityGiftCell.cs 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityPopWin.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityRechargeBaseWin.cs 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityRechargeTotDayCell.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityRechargeTotalCell.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityShopCell.cs 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/FestivalActivity/FestivalActivityWin.cs 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Horse/HorseController.cs 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Main/HomeWin.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/ConfigManager.cs
@@ -17,12 +17,16 @@
        private set;
    }
    private List<Type> preInitConfig = new List<Type>()
    {
      typeof (FuncConfigConfig),
    };
    private float loadingProgress = 0f;
    public override void Init()
    public override async UniTask Init()
    {
        base.Init();
        InitConfigs();
        await InitConfigs();
    }
    public virtual async UniTask InitConfigs()
@@ -31,21 +35,34 @@
        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;
        // 加载配置文件
        // 加载配置文件
        // 加载配置文件
        // 加载配置文件
        HashSet<Type> configTypes = new HashSet<Type>() {
            typeof(ActBillboardAwardConfig),
            typeof(ActHeroAppearArtConfig),
            typeof(ActHeroAppearConfig),
            typeof(ActHeroAppearArtConfig),
            typeof(ActHeroAppearStarConfig),
            typeof(ActHeroReturnArtConfig),
            typeof(ActLunhuidianTypeConfig),
            typeof(ActSignAwardConfig),
            typeof(ActSignConfig),
            typeof(ActSignAwardConfig),
            typeof(ActSpecialSaleConfig),
            typeof(ActTaskConfig),
            typeof(ActTaskTempConfig),
@@ -54,45 +71,76 @@
            typeof(ActTotDayRechargeConfig),
            typeof(ActTotDayRechargeTempConfig),
            typeof(ADAwardConfig),
            typeof(AppointItemConfig),
            typeof(AudioConfig),
            typeof(BattleMapConfig),
            typeof(BeautyConfig),
            typeof(BeautyQualityLVConfig),
            typeof(BeautySkinConfig),
            typeof(ChatBubbleBoxConfig),
            typeof(ChestsConfig),
            typeof(ChestsAwardConfig),
            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(FuncOpenLVConfig),
            typeof(FunctionTeamSetConfig),
            typeof(GetItemWaysConfig),
            typeof(GmCmdConfig),
            typeof(GoldRushCampConfig),
            typeof(GoldRushItemConfig),
            typeof(GoldRushWorkerConfig),
            typeof(GubaoConfig),
            typeof(GubaoLVAttrConfig),
            typeof(GubaoLVConfig),
            typeof(GubaoResonanceAttrConfig),
            typeof(GubaoLVAttrConfig),
            typeof(GubaoResonanceConfig),
            typeof(GubaoResonanceAttrConfig),
            typeof(GubaoStarConfig),
            typeof(GuideConfig),
            typeof(HeroConfig),
            typeof(HeroAwakeConfig),
            typeof(HeroBreakConfig),
            typeof(HeroFatesConfig),
            typeof(HeroFatesQualityLVConfig),
            typeof(HeroFetterConfig),
            typeof(HeroLineupHaloConfig),
            typeof(HeroQualityConfig),
            typeof(HeroQualityAwakeConfig),
            typeof(HeroQualityBreakConfig),
            typeof(HeroQualityLVConfig),
            typeof(HeroSkinConfig),
            typeof(HeroSkinAttrConfig),
            typeof(HeroTalentConfig),
            typeof(HorseClassConfig),
            typeof(HorseIDConfig),
            typeof(HorseSkinConfig),
            typeof(ItemCompoundConfig),
            typeof(IconConfig),
            typeof(ItemConfig),
            typeof(ItemCompoundConfig),
            typeof(KickOutReasonConfig),
            typeof(LanguageConfig),
            typeof(LineupRecommendConfig),
            typeof(LLMJConfig),
            typeof(MailConfig),
            typeof(MainChapterConfig),
            typeof(MainLevelConfig),
            typeof(MGGanwuLVConfig),
@@ -107,16 +155,25 @@
            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(RobotConfig),
            typeof(RuleConfig),
            typeof(SignInConfig),
            typeof(SkillConfig),
            typeof(SkillSkinConfig),
            typeof(StoreConfig),
            typeof(SuccessConfig),
            typeof(SysInfoConfig),
            typeof(TaskConfig),
            typeof(TianziConfig),
            typeof(TimingGiftConfig),
            typeof(TimingGiftTypeConfig),
@@ -124,6 +181,8 @@
            typeof(TitleStarUpConfig),
            typeof(TravelEventConfig),
            typeof(TravelSceneryConfig),
            typeof(TreasureCntAwardConfig),
            typeof(TreasureItemLibConfig),
            typeof(TreasureSetConfig),
            typeof(TreeLVConfig),
            typeof(WindowSearchConfig),
@@ -131,64 +190,85 @@
            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();
            LoadConfigByType(configType);
            sw.Stop();
#if UNITY_EDITOR
            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++ + 1) / totalConfigs;
        }
#if UNITY_EDITOR
        if (Launch.Instance.isOpenConfigTesting)
        {
            System.IO.File.WriteAllText(Application.dataPath + "/fastConfig.txt", string.Join("\n", fastName));
            //加载完后卸载
            foreach (var configType in configTypes)
            UniTask uniTask = LoadConfigByTypeAsync(configType).ContinueWith(() =>
            {
                var methodInfo = configType.GetMethod("ForceRelease", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.FlattenHierarchy);
                if (methodInfo != null)
#if UNITY_EDITOR
                if (sw.ElapsedMilliseconds >= 100)
                {
                    methodInfo.Invoke(null, null);
                    Debug.LogWarning($"加载配置 {configType.Name} 耗时较长: {sw.ElapsedMilliseconds} ms");
                }
            }
                else
                {
                    Debug.Log($"加载配置: {configType.Name} 用时: {sw.ElapsedMilliseconds} ms");
                }
                sw.Stop();
#endif
                loadingProgress = (float)(++iterator) / totalConfigs;
            });
            loadTasks.Add(uniTask);
        }
        await UniTask.WhenAll(loadTasks);
#endif
        // 加载完成后设置isLoadFinished为true
@@ -196,28 +276,64 @@
        isLoadFinished = true;
    }
    public void LoadConfigByType(Type configType)
    // 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)
    {
        string configName = configType.Name;
        if (configName.EndsWith("Config"))
        {
            configName = configName.Substring(0, configName.Length - 6);
        }
        string[] texts = ResManager.Instance.LoadConfig(configName);
        string[] texts = await ResManager.Instance.LoadConfigAsync(configName);
        if (texts != null)
        {
            string[] lines = texts;
            var methodInfo = configType.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 });
                // 设置初始化标志
                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);
                }
                Debug.Log($"加载配置: {configType.Name} 成功");
            }
            else
            {
@@ -230,36 +346,38 @@
        }
    }
    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;
        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}");
        }
    }
    //     #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}");
    //     }
    // }
    public float GetLoadingProgress()
    {
@@ -280,20 +398,20 @@
    {
        // 清空 ActBillboardAwardConfig 字典
        ClearConfigDictionary<ActBillboardAwardConfig>();
        // 清空 ActHeroAppearArtConfig 字典
        ClearConfigDictionary<ActHeroAppearArtConfig>();
        // 清空 ActHeroAppearConfig 字典
        ClearConfigDictionary<ActHeroAppearConfig>();
        // 清空 ActHeroAppearArtConfig 字典
        ClearConfigDictionary<ActHeroAppearArtConfig>();
        // 清空 ActHeroAppearStarConfig 字典
        ClearConfigDictionary<ActHeroAppearStarConfig>();
        // 清空 ActHeroReturnArtConfig 字典
        ClearConfigDictionary<ActHeroReturnArtConfig>();
        // 清空 ActLunhuidianTypeConfig 字典
        ClearConfigDictionary<ActLunhuidianTypeConfig>();
        // 清空 ActSignAwardConfig 字典
        ClearConfigDictionary<ActSignAwardConfig>();
        // 清空 ActSignConfig 字典
        ClearConfigDictionary<ActSignConfig>();
        // 清空 ActSignAwardConfig 字典
        ClearConfigDictionary<ActSignAwardConfig>();
        // 清空 ActSpecialSaleConfig 字典
        ClearConfigDictionary<ActSpecialSaleConfig>();
        // 清空 ActTaskConfig 字典
@@ -310,6 +428,10 @@
        ClearConfigDictionary<ActTotDayRechargeTempConfig>();
        // 清空 ADAwardConfig 字典
        ClearConfigDictionary<ADAwardConfig>();
        // 清空 AppointItemConfig 字典
        ClearConfigDictionary<AppointItemConfig>();
        // 清空 AudioConfig 字典
        ClearConfigDictionary<AudioConfig>();
        // 清空 BattleMapConfig 字典
        ClearConfigDictionary<BattleMapConfig>();
        // 清空 BeautyConfig 字典
@@ -318,24 +440,42 @@
        ClearConfigDictionary<BeautyQualityLVConfig>();
        // 清空 BeautySkinConfig 字典
        ClearConfigDictionary<BeautySkinConfig>();
        // 清空 ChatBubbleBoxConfig 字典
        ClearConfigDictionary<ChatBubbleBoxConfig>();
        // 清空 ChestsConfig 字典
        ClearConfigDictionary<ChestsConfig>();
        // 清空 ChestsAwardConfig 字典
        ClearConfigDictionary<ChestsAwardConfig>();
        // 清空 CTGConfig 字典
        ClearConfigDictionary<CTGConfig>();
        // 清空 CTGSelectItemConfig 字典
        ClearConfigDictionary<CTGSelectItemConfig>();
        // 清空 DailyLivenessRewardConfig 字典
        ClearConfigDictionary<DailyLivenessRewardConfig>();
        // 清空 DailyTaskConfig 字典
        ClearConfigDictionary<DailyTaskConfig>();
        // 清空 DamageNumConfig 字典
        ClearConfigDictionary<DamageNumConfig>();
        // 清空 DirtyNameConfig 字典
        ClearConfigDictionary<DirtyNameConfig>();
        // 清空 DirtyWordConfig 字典
        ClearConfigDictionary<DirtyWordConfig>();
        // 清空 DungeonConfig 字典
        ClearConfigDictionary<DungeonConfig>();
        // 清空 DungeonOpenTimeConfig 字典
        ClearConfigDictionary<DungeonOpenTimeConfig>();
        // 清空 EffectConfig 字典
        ClearConfigDictionary<EffectConfig>();
        // 清空 EmojiPackConfig 字典
        ClearConfigDictionary<EmojiPackConfig>();
        // 清空 FaceConfig 字典
        ClearConfigDictionary<FaceConfig>();
        // 清空 FamilyConfig 字典
        ClearConfigDictionary<FamilyConfig>();
        // 清空 FamilyDonateConfig 字典
        ClearConfigDictionary<FamilyDonateConfig>();
        // 清空 FamilyEmblemConfig 字典
        ClearConfigDictionary<FamilyEmblemConfig>();
        // 清空 FBDJGEffectConfig 字典
        ClearConfigDictionary<FBDJGEffectConfig>();
        // 清空 FBDJGLevelConfig 字典
@@ -346,6 +486,18 @@
        ClearConfigDictionary<FightPowerRatioConfig>();
        // 清空 FirstChargeConfig 字典
        ClearConfigDictionary<FirstChargeConfig>();
        // 清空 FirstGoldConfig 字典
        ClearConfigDictionary<FirstGoldConfig>();
        // 清空 FrameAnimationConfig 字典
        ClearConfigDictionary<FrameAnimationConfig>();
        // 清空 FuncOpenLVConfig 字典
        ClearConfigDictionary<FuncOpenLVConfig>();
        // 清空 FunctionTeamSetConfig 字典
        ClearConfigDictionary<FunctionTeamSetConfig>();
        // 清空 GetItemWaysConfig 字典
        ClearConfigDictionary<GetItemWaysConfig>();
        // 清空 GmCmdConfig 字典
        ClearConfigDictionary<GmCmdConfig>();
        // 清空 GoldRushCampConfig 字典
        ClearConfigDictionary<GoldRushCampConfig>();
        // 清空 GoldRushItemConfig 字典
@@ -354,40 +506,68 @@
        ClearConfigDictionary<GoldRushWorkerConfig>();
        // 清空 GubaoConfig 字典
        ClearConfigDictionary<GubaoConfig>();
        // 清空 GubaoLVAttrConfig 字典
        ClearConfigDictionary<GubaoLVAttrConfig>();
        // 清空 GubaoLVConfig 字典
        ClearConfigDictionary<GubaoLVConfig>();
        // 清空 GubaoResonanceAttrConfig 字典
        ClearConfigDictionary<GubaoResonanceAttrConfig>();
        // 清空 GubaoLVAttrConfig 字典
        ClearConfigDictionary<GubaoLVAttrConfig>();
        // 清空 GubaoResonanceConfig 字典
        ClearConfigDictionary<GubaoResonanceConfig>();
        // 清空 GubaoResonanceAttrConfig 字典
        ClearConfigDictionary<GubaoResonanceAttrConfig>();
        // 清空 GubaoStarConfig 字典
        ClearConfigDictionary<GubaoStarConfig>();
        // 清空 GuideConfig 字典
        ClearConfigDictionary<GuideConfig>();
        // 清空 HeroConfig 字典
        ClearConfigDictionary<HeroConfig>();
        // 清空 HeroAwakeConfig 字典
        ClearConfigDictionary<HeroAwakeConfig>();
        // 清空 HeroBreakConfig 字典
        ClearConfigDictionary<HeroBreakConfig>();
        // 清空 HeroFatesConfig 字典
        ClearConfigDictionary<HeroFatesConfig>();
        // 清空 HeroFatesQualityLVConfig 字典
        ClearConfigDictionary<HeroFatesQualityLVConfig>();
        // 清空 HeroFetterConfig 字典
        ClearConfigDictionary<HeroFetterConfig>();
        // 清空 HeroLineupHaloConfig 字典
        ClearConfigDictionary<HeroLineupHaloConfig>();
        // 清空 HeroQualityConfig 字典
        ClearConfigDictionary<HeroQualityConfig>();
        // 清空 HeroQualityAwakeConfig 字典
        ClearConfigDictionary<HeroQualityAwakeConfig>();
        // 清空 HeroQualityBreakConfig 字典
        ClearConfigDictionary<HeroQualityBreakConfig>();
        // 清空 HeroQualityLVConfig 字典
        ClearConfigDictionary<HeroQualityLVConfig>();
        // 清空 HeroSkinConfig 字典
        ClearConfigDictionary<HeroSkinConfig>();
        // 清空 HeroSkinAttrConfig 字典
        ClearConfigDictionary<HeroSkinAttrConfig>();
        // 清空 HeroTalentConfig 字典
        ClearConfigDictionary<HeroTalentConfig>();
        // 清空 HorseClassConfig 字典
        ClearConfigDictionary<HorseClassConfig>();
        // 清空 HorseIDConfig 字典
        ClearConfigDictionary<HorseIDConfig>();
        // 清空 HorseSkinConfig 字典
        ClearConfigDictionary<HorseSkinConfig>();
        // 清空 ItemCompoundConfig 字典
        ClearConfigDictionary<ItemCompoundConfig>();
        // 清空 IconConfig 字典
        ClearConfigDictionary<IconConfig>();
        // 清空 ItemConfig 字典
        ClearConfigDictionary<ItemConfig>();
        // 清空 ItemCompoundConfig 字典
        ClearConfigDictionary<ItemCompoundConfig>();
        // 清空 KickOutReasonConfig 字典
        ClearConfigDictionary<KickOutReasonConfig>();
        // 清空 LanguageConfig 字典
        ClearConfigDictionary<LanguageConfig>();
        // 清空 LineupRecommendConfig 字典
        ClearConfigDictionary<LineupRecommendConfig>();
        // 清空 LLMJConfig 字典
        ClearConfigDictionary<LLMJConfig>();
        // 清空 MailConfig 字典
        ClearConfigDictionary<MailConfig>();
        // 清空 MainChapterConfig 字典
        ClearConfigDictionary<MainChapterConfig>();
        // 清空 MainLevelConfig 字典
@@ -416,6 +596,12 @@
        ClearConfigDictionary<PlayerAttrConfig>();
        // 清空 PlayerFaceConfig 字典
        ClearConfigDictionary<PlayerFaceConfig>();
        // 清空 PlayerFacePicConfig 字典
        ClearConfigDictionary<PlayerFacePicConfig>();
        // 清空 PlayerLVConfig 字典
        ClearConfigDictionary<PlayerLVConfig>();
        // 清空 PlayerPropertyConfig 字典
        ClearConfigDictionary<PlayerPropertyConfig>();
        // 清空 PopWinOrderConfig 字典
        ClearConfigDictionary<PopWinOrderConfig>();
        // 清空 PresetUnlockConfig 字典
@@ -424,10 +610,20 @@
        ClearConfigDictionary<PriorBundleConfig>();
        // 清空 RandomNameConfig 字典
        ClearConfigDictionary<RandomNameConfig>();
        // 清空 RealmConfig 字典
        ClearConfigDictionary<RealmConfig>();
        // 清空 RealmLVUPTaskConfig 字典
        ClearConfigDictionary<RealmLVUPTaskConfig>();
        // 清空 RichTextMsgReplaceConfig 字典
        ClearConfigDictionary<RichTextMsgReplaceConfig>();
        // 清空 RobotConfig 字典
        ClearConfigDictionary<RobotConfig>();
        // 清空 RuleConfig 字典
        ClearConfigDictionary<RuleConfig>();
        // 清空 SignInConfig 字典
        ClearConfigDictionary<SignInConfig>();
        // 清空 SkillConfig 字典
        ClearConfigDictionary<SkillConfig>();
        // 清空 SkillSkinConfig 字典
        ClearConfigDictionary<SkillSkinConfig>();
        // 清空 StoreConfig 字典
@@ -436,6 +632,8 @@
        ClearConfigDictionary<SuccessConfig>();
        // 清空 SysInfoConfig 字典
        ClearConfigDictionary<SysInfoConfig>();
        // 清空 TaskConfig 字典
        ClearConfigDictionary<TaskConfig>();
        // 清空 TianziConfig 字典
        ClearConfigDictionary<TianziConfig>();
        // 清空 TimingGiftConfig 字典
@@ -450,6 +648,10 @@
        ClearConfigDictionary<TravelEventConfig>();
        // 清空 TravelSceneryConfig 字典
        ClearConfigDictionary<TravelSceneryConfig>();
        // 清空 TreasureCntAwardConfig 字典
        ClearConfigDictionary<TreasureCntAwardConfig>();
        // 清空 TreasureItemLibConfig 字典
        ClearConfigDictionary<TreasureItemLibConfig>();
        // 清空 TreasureSetConfig 字典
        ClearConfigDictionary<TreasureSetConfig>();
        // 清空 TreeLVConfig 字典
@@ -462,9 +664,22 @@
        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
    [MenuItem("Tools/Config/自检")]
    public static void CheckAndGenerateFastConfig()
    /// <summary>
    /// Editor 自检:反射加载所有配置类并记录耗时。
    /// </summary>
    public async void SelfCheckAllConfigs()
    {
        // 获取 Editor Assembly
        var editorAsm = System.AppDomain.CurrentDomain.GetAssemblies()
@@ -505,8 +720,8 @@
        foreach (var className in checkClasses)
        {
            // 这里也要用 Editor Assembly 获取类型
            var configType = editorAsm.GetType(className) ?? Type.GetType(className);
            if (configType == null)
            var cfgType = editorAsm.GetType(className) ?? Type.GetType(className);
            if (cfgType == null)
            {
                Debug.LogWarning($"[自检] 未找到类型: {className}");
                continue;
@@ -515,15 +730,15 @@
            var sw = System.Diagnostics.Stopwatch.StartNew();
            // 反射调用静态Init方法
            string configName = configType.Name;
            string configName = cfgType.Name;
            if (configName.EndsWith("Config"))
                configName = configName.Substring(0, configName.Length - 6);
            string[] texts = ResManager.Instance.LoadConfig(configName);
            string[] texts = await ResManager.Instance.LoadConfigAsync(configName);
            if (texts != null)
            {
                string[] lines = texts;
                var methodInfo = configType.GetMethod("Init", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.FlattenHierarchy);
                var methodInfo = cfgType.GetMethod("Init", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.FlattenHierarchy);
                if (methodInfo != null)
                {
                    methodInfo.Invoke(null, new object[] { lines });
@@ -534,21 +749,21 @@
            if (sw.ElapsedMilliseconds >= 500)
            {
                Debug.LogError($"[自检] 加载配置 {configType.Name} 耗时较长: {sw.ElapsedMilliseconds} ms");
                Debug.LogError($"[自检] 加载配置 {cfgType.Name} 耗时较长: {sw.ElapsedMilliseconds} ms");
            }
            else if (sw.ElapsedMilliseconds <= 5)
            {
                fastName.Add(configType.Name);
                fastName.Add(cfgType.Name);
            }
            Debug.Log($"[自检] 加载配置: {configType.Name} 用时: {sw.ElapsedMilliseconds} ms");
            Debug.Log($"[自检] 加载配置: {cfgType.Name} 用时: {sw.ElapsedMilliseconds} ms");
        }
        // 释放所有已加载的配置
        foreach (var className in checkClasses)
        {
            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);
            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);
            if (methodInfo != null)
            {
                methodInfo.Invoke(null, null);
@@ -559,4 +774,26 @@
        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/Core/NetworkPackage/Socket/ClientSocket.cs
@@ -219,11 +219,13 @@
            if (m_packageThread != null)
            {
                m_packageThread.Abort();
                m_packageThread = null;
            }
        }
        catch (System.Exception ex)
        {
            Debug.Log(ex);
            m_packageThread = null;
        }
        try
@@ -250,29 +252,19 @@
    {
        if (m_packageThread != null)
        {
            m_packageThread.Abort();
            m_packageThread = null;
        }
        m_LastPackageTime = DateTime.Now;
        m_packageThread = new Thread(new ThreadStart(ReceiveInfo)); // 启动线程接收信息
        m_packageThread.IsBackground = true;
        m_packageThread.Start();
        isStopTreading = false;
        Debug.unityLogger.logEnabled = true;
        Debug.Log("[ClientSocket][OnConnectSuccess] 连接成功,启动接收线程");
        if (m_packageThread != null)
        {
            Debug.LogWarning("[ClientSocket][OnConnectSuccess] m_packageThread已存在,先Abort");
            m_packageThread.Abort();
            m_packageThread = null;
        }
        fragmentBytes = null; // 清除上次连接残留的碎片缓存
        m_LastPackageTime = DateTime.Now;
        isStopTreading = false;
        m_packageThread = new Thread(new ThreadStart(ReceiveInfo)); // 启动线程接收信息
        m_packageThread.IsBackground = true;
        m_packageThread.Start();
        isStopTreading = false;
        Debug.unityLogger.logEnabled = true;
        Debug.Log("[ClientSocket][OnConnectSuccess] 连接成功,启动接收线程");
    }
    /// <summary>
@@ -280,44 +272,6 @@
    /// </summary>
    private void ReceiveInfo()
    {
        while (!isStopTreading)
        {
            try
            {
                var shutdown = false;
                if (!m_Socket.Connected)
                {
                    shutdown = true;
                }
                if (!shutdown)
                {
                    var dataLength = m_Socket.Receive(bufferBytes);
                    if (dataLength <= 0)
                    {
                        shutdown = true;
                    }
                    else
                    {
                        getBytesTotal += dataLength;
                        var bytes = new byte[dataLength];
                        Array.Copy(bufferBytes, 0, bytes, 0, dataLength);
                        ReadInfo(bytes);
                    }
                }
                if (shutdown)
                {
                    isStopTreading = true;
                    m_Socket.Shutdown(SocketShutdown.Both);
                    m_Socket.Close();
                }
            }
            catch (Exception e)
            {
                Debug.Log(e);
            }
        }
        Debug.unityLogger.logEnabled = true;
        Debug.Log("[ClientSocket][ReceiveInfo] 接收线程启动");
        while (!isStopTreading)
@@ -401,9 +355,21 @@
                    Array.Copy(fixBytes, vReadIndex, fragmentBytes, 0, vLeavingLeng);
                    break;
                }
                // 打印包头原始字节,便于排查 OverflowException
                byte h0 = fixBytes[vReadIndex], h1 = fixBytes[vReadIndex + 1],
                     h2 = fixBytes[vReadIndex + 2], h3 = fixBytes[vReadIndex + 3],
                     h4 = fixBytes[vReadIndex + 4], h5 = fixBytes[vReadIndex + 5];
                vBodyLeng = BitConverter.ToInt32(fixBytes, vReadIndex + 2);
                Debug.Log($"[ClientSocket][ReadInfo] vReadIndex={vReadIndex} vTotalLeng={vTotalLeng} vLeavingLeng={vLeavingLeng} header=[{h0:X2} {h1:X2} {h2:X2} {h3:X2} {h4:X2} {h5:X2}] vBodyLeng={vBodyLeng}");
                if (vBodyLeng < 0)
                {
                    Debug.LogError($"[ClientSocket][ReadInfo] vBodyLeng异常({vBodyLeng}),丢弃剩余数据!fragmentBytes总长={fixBytes.Length} vReadIndex={vReadIndex}");
                    fragmentBytes = null;
                    break;
                }
                if (vBodyLeng > vLeavingLeng - 6)// 未完整的包则留包
                {
                    Debug.Log($"[ClientSocket][ReadInfo] 包不完整,留包: vBodyLeng={vBodyLeng} vLeavingLeng={vLeavingLeng}");
                    fragmentBytes = new byte[vLeavingLeng];
                    Array.Copy(fixBytes, vReadIndex, fragmentBytes, 0, vLeavingLeng);
                    break;
Main/System/Arena/ArenaBattleFailWin.cs
@@ -69,8 +69,8 @@
        myAvatarCell.InitUI(AvatarHelper.GetAvatarModel((int)PlayerDatas.Instance.baseData.PlayerID,
                                                PlayerDatas.Instance.baseData.face,
                                                PlayerDatas.Instance.baseData.facePic));
        enemyAvatarCell.InitUI(AvatarHelper.GetAvatarModel((int)tagPlayerID, (int)enemyFace, (int)enemyFacePic));
                                                PlayerDatas.Instance.baseData.facePic)).Forget();
        enemyAvatarCell.InitUI(AvatarHelper.GetAvatarModel((int)tagPlayerID, (int)enemyFace, (int)enemyFacePic)).Forget();
        enemyAvatarCell.SetListener(() =>
        {
            int serverID = (ArenaManager.Instance.IsOpenCrossServer() && tagPlayerID != PlayerDatas.Instance.baseData.PlayerID) ? (int)info.ServerID : 0;
Main/System/Arena/ArenaBattleVictoryWin.cs
@@ -63,8 +63,8 @@
        myAvatarCell.InitUI(AvatarHelper.GetAvatarModel((int)PlayerDatas.Instance.baseData.PlayerID,
                                                PlayerDatas.Instance.baseData.face,
                                                PlayerDatas.Instance.baseData.facePic));
        enemyAvatarCell.InitUI(AvatarHelper.GetAvatarModel((int)tagPlayerID, (int)enemyFace, (int)enemyFacePic));
                                                PlayerDatas.Instance.baseData.facePic)).Forget();
        enemyAvatarCell.InitUI(AvatarHelper.GetAvatarModel((int)tagPlayerID, (int)enemyFace, (int)enemyFacePic)).Forget();
        enemyAvatarCell.SetListener(() =>
        {
            int serverID = (ArenaManager.Instance.IsOpenCrossServer() && tagPlayerID != PlayerDatas.Instance.baseData.PlayerID) ? (int)info.ServerID : 0;
Main/System/Arena/ArenaChallengeCell.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using UnityEngine;
public class ArenaChallengeCell : MonoBehaviour
@@ -34,7 +35,8 @@
            return;
        arenaMatchInfo = list[index];
        avatarCell.InitUI(AvatarHelper.GetAvatarModel((int)arenaMatchInfo.PlayerID, (int)arenaMatchInfo.Face, (int)arenaMatchInfo.FacePic));
        avatarCell.InitUI(
            AvatarHelper.GetAvatarModel((int)arenaMatchInfo.PlayerID, (int)arenaMatchInfo.Face, (int)arenaMatchInfo.FacePic)).Forget();
        avatarCell.SetListener(() =>
        {
            int serverID = (ArenaManager.Instance.IsOpenCrossServer() && arenaMatchInfo.PlayerID != PlayerDatas.Instance.baseData.PlayerID) ? (int)arenaMatchInfo.ServerID : 0;
@@ -64,7 +66,7 @@
            txtAddCrossScore.SetActive(false);
        }
        
        officialTitleCell.InitUI(arenaMatchInfo.RealmLV, (int)arenaMatchInfo.TitleID, 0.55f);
        officialTitleCell.InitUI(arenaMatchInfo.RealmLV, (int)arenaMatchInfo.TitleID, 0.55f).Forget();
        int[][] rewards = ArenaManager.Instance.fixedChallengeRewards;
        for (int i = 0; i < itemCells.Count; i++)
Main/System/Arena/ArenaPlayerRankCell.cs
@@ -1,3 +1,4 @@
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
@@ -39,11 +40,11 @@
                //取玩家自己的数据
                avatarCell.InitUI(AvatarHelper.GetAvatarModel((int)PlayerDatas.Instance.baseData.PlayerID,
                                                PlayerDatas.Instance.baseData.face,
                                                PlayerDatas.Instance.baseData.facePic));
                                                PlayerDatas.Instance.baseData.facePic)).Forget();
                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);
                officialTitleCell.InitUI(PlayerDatas.Instance.baseData.realmLevel, PlayerDatas.Instance.baseData.TitleID).Forget();
                return;
            }
            rank = rankData.rank;
@@ -61,9 +62,9 @@
        {
            viewPlayerId = (int)rankData.id;
            officialTitleCell.SetActive(true);
            officialTitleCell.InitUI((int)rankData.value1, (int)rankData.value2);
            officialTitleCell.InitUI((int)rankData.value1, (int)rankData.value2).Forget();
            avatarCell.SetActive(true);
            avatarCell.InitUI(AvatarHelper.GetAvatarModel((int)rankData.id, (int)rankData.value3, (int)rankData.value4));
            avatarCell.InitUI(AvatarHelper.GetAvatarModel((int)rankData.id, (int)rankData.value3, (int)rankData.value4)).Forget();
            // 跨服显示服务器名称
            if (isCross && serverText != null)
Main/System/Arena/ArenaPlayerTop3Cell.cs
@@ -1,3 +1,4 @@
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
@@ -37,8 +38,8 @@
        officialTitleCell.SetActive(true);
        rankValueText.text = string.Format(valueFormat, UIHelper.ReplaceLargeNum(rankData.cmpValue));
        nameText.text = rankData.name1;
        officialTitleCell.InitUI((int)rankData.value1, (int)rankData.value2);
        model.Create(HorseManager.Instance.GetOtherPlayerHorseSkinID((int)rankData.value6), (int)rankData.value5, 1);
        officialTitleCell.InitUI((int)rankData.value1, (int)rankData.value2).Forget();
        model.Create(HorseManager.Instance.GetOtherPlayerHorseSkinID((int)rankData.value6), (int)rankData.value5, 1).Forget();
        if (isCross && serverText != null)
        {
Main/System/Arena/ArenaRecordCell.cs
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using UnityEngine;
using System;
using Cysharp.Threading.Tasks;
public class ArenaRecordCell : MonoBehaviour
{
@@ -99,7 +100,8 @@
            }
        }
        avatarCell.InitUI(AvatarHelper.GetAvatarModel((int)arenaGameRec.Value3, (int)arenaGameRec.Value5, (int)arenaGameRec.Value6));
        avatarCell.InitUI(
            AvatarHelper.GetAvatarModel((int)arenaGameRec.Value3, (int)arenaGameRec.Value5, (int)arenaGameRec.Value6)).Forget();
        avatarCell.SetListener(() =>
        {
            int serverID = (ArenaManager.Instance.IsOpenCrossServer() && arenaGameRec.Value3 != PlayerDatas.Instance.baseData.PlayerID) ? (int)arenaGameRec.ServerID : 0;
@@ -107,7 +109,7 @@
        });
        txtName.text = arenaGameRec.Name;
        txtFightPoint.text = UIHelper.ReplaceLargeArtNum(arenaGameRec.FightPower);
        officialTitleCell.InitUI(PlayerDatas.Instance.baseData.realmLevel, PlayerDatas.Instance.baseData.TitleID, 0.55f);
        officialTitleCell.InitUI(PlayerDatas.Instance.baseData.realmLevel, PlayerDatas.Instance.baseData.TitleID, 0.55f).Forget();
        imgMoneyIcon.SetIconWithMoneyType(ArenaManager.Instance.ChallengeMoneyType);
        txtNeedCount.text = ArenaManager.Instance.NeedChallengeMoneyCnt.ToString();
    }
Main/System/Arena/ArenaWin.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
@@ -49,19 +50,19 @@
        btnAward.SetListener(() =>
        {
            if (ArenaManager.Instance.IsOpenCrossServer())
                UIManager.Instance.OpenWindow<ArenaCrossAwardWin>();
                UIManager.Instance.OpenWindowAsync<ArenaCrossAwardWin>().Forget();
            else
                UIManager.Instance.OpenWindow<ArenaAwardWin>();
                UIManager.Instance.OpenWindowAsync<ArenaAwardWin>().Forget();
        });
        btnRecord.SetListener(() =>
        {
            ArenaManager.Instance.SendViewGameRecPack();
            UIManager.Instance.OpenWindow<ArenaRecordWin>();
            UIManager.Instance.OpenWindowAsync<ArenaRecordWin>().Forget();
        });
        btnChallage.SetListener(() =>
        {
            ArenaManager.Instance.SendArenaMatch();
            UIManager.Instance.OpenWindow<ArenaChallengeWin>();
            UIManager.Instance.OpenWindowAsync<ArenaChallengeWin>().Forget();
        });
        funPresetBtn.AddListener(() =>
        {
@@ -70,9 +71,9 @@
        btnCrossAward.SetListener(() =>
        {
            if (ArenaManager.Instance.IsOpenCrossServer())
                UIManager.Instance.OpenWindow<ArenaCrossAwardWin>();
                UIManager.Instance.OpenWindowAsync<ArenaCrossAwardWin>().Forget();
            else
                UIManager.Instance.OpenWindow<ArenaAwardWin>();
                UIManager.Instance.OpenWindowAsync<ArenaAwardWin>().Forget();
        });
        btnFunPresetCross.AddListener(() =>
        {
@@ -82,17 +83,17 @@
        // 跨服按钮监听器
        btnAwardCross.SetListener(() =>
        {
            UIManager.Instance.OpenWindow<ArenaCrossAwardWin>();
            UIManager.Instance.OpenWindowAsync<ArenaCrossAwardWin>().Forget();
        });
        btnRecordCross.SetListener(() =>
        {
            ArenaManager.Instance.SendViewGameRecPack();
            UIManager.Instance.OpenWindow<ArenaRecordWin>();
            UIManager.Instance.OpenWindowAsync<ArenaRecordWin>().Forget();
        });
        btnChallageCross.SetListener(() =>
        {
            ArenaManager.Instance.SendArenaMatch();
            UIManager.Instance.OpenWindow<ArenaChallengeWin>();
            UIManager.Instance.OpenWindowAsync<ArenaChallengeWin>().Forget();
        });
        funPresetBtnCross.AddListener(() =>
        {
Main/System/FestivalActivity/FestivalActivityGiftCell.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using UnityEngine;
public class FestivalActivityGiftCell : MonoBehaviour
@@ -91,13 +92,13 @@
            if (config.VipLevel == 1 && !InvestModel.Instance.IsInvested(InvestModel.monthCardType))
            {
                SysNotifyMgr.Instance.ShowTip("MinggeAuto5");
                UIManager.Instance.OpenWindow<PrivilegeCardWin>();
                UIManager.Instance.OpenWindowAsync<PrivilegeCardWin>().Forget();
                return;
            }
            if (config.VipLevel == 2 && !InvestModel.Instance.IsInvested(InvestModel.foreverCardType))
            {
                SysNotifyMgr.Instance.ShowTip("MinggeAuto7");
                UIManager.Instance.OpenWindow<PrivilegeCardWin>();
                UIManager.Instance.OpenWindowAsync<PrivilegeCardWin>().Forget();
                return;
            }
            RechargeManager.Instance.CTG(ctgId);
Main/System/FestivalActivity/FestivalActivityPopWin.cs
@@ -1,3 +1,4 @@
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
@@ -17,7 +18,7 @@
        {
            UIManager.Instance.CloseWindow<FestivalActivityPopWin>();
            if (!UIManager.Instance.IsOpened<FestivalActivityWin>())
                UIManager.Instance.OpenWindow<FestivalActivityWin>();
                UIManager.Instance.OpenWindowAsync<FestivalActivityWin>().Forget();
        });
        todayPopToggle.AddListener((bool value) =>
        {
Main/System/FestivalActivity/FestivalActivityRechargeBaseWin.cs
@@ -1,4 +1,5 @@
using System;
using Cysharp.Threading.Tasks;
using UnityEngine;
public class FestivalActivityRechargeBaseWin : FunctionsBaseWin
{
@@ -24,15 +25,15 @@
        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
    }
    protected override void OpenSubUIByTabIndex()
    protected override async void OpenSubUIByTabIndex()
    {
        switch (functionOrder)
        {
            case 0:
                currentSubUI = UIManager.Instance.OpenWindow<FestivalActivityRechargeTotalWin>();
                currentSubUI = await UIManager.Instance.OpenWindowAsync<FestivalActivityRechargeTotalWin>();
                break;
            case 1:
                currentSubUI = UIManager.Instance.OpenWindow<FestivalActivityRechargeTotDayWin>();
                currentSubUI = await UIManager.Instance.OpenWindowAsync<FestivalActivityRechargeTotDayWin>();
                break;
        }
    }
Main/System/FestivalActivity/FestivalActivityRechargeTotDayCell.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
@@ -66,7 +67,7 @@
                }
                else
                {
                    UIManager.Instance.OpenWindow<StoreBaseWin>(2);
                    UIManager.Instance.OpenWindowAsync<StoreBaseWin>(2).Forget();
                }
            }
        });
Main/System/FestivalActivity/FestivalActivityRechargeTotalCell.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
@@ -66,7 +67,7 @@
                }
                else
                {
                    UIManager.Instance.OpenWindow<StoreBaseWin>(2);
                    UIManager.Instance.OpenWindowAsync<StoreBaseWin>(2).Forget();
                }
            }
        });
Main/System/FestivalActivity/FestivalActivityShopCell.cs
@@ -1,4 +1,5 @@
using UnityEngine;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
public class FestivalActivityShopCell : MonoBehaviour
@@ -126,7 +127,7 @@
        else
        {
            StoreModel.Instance.buyShopID = shopID;
            UIManager.Instance.OpenWindow<BuyItemWin>();
            UIManager.Instance.OpenWindowAsync<BuyItemWin>().Forget();
        }
    }
}
Main/System/FestivalActivity/FestivalActivityWin.cs
@@ -1,3 +1,4 @@
using Cysharp.Threading.Tasks;
using UnityEngine;
public class FestivalActivityWin : UIBase
{
@@ -22,11 +23,11 @@
    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>());
        checkInButton.SetListener(() => UIManager.Instance.OpenWindowAsync<FestivalActivityCheckInWin>().Forget());
        missionButton.SetListener(() => UIManager.Instance.OpenWindowAsync<FestivalActivityMissionWin>().Forget());
        shopButton.SetListener(() => UIManager.Instance.OpenWindowAsync<FestivalActivityShopWin>().Forget());
        giftButton.SetListener(() => UIManager.Instance.OpenWindowAsync<FestivalActivityGiftWin>().Forget());
        rechargeButton.SetListener(() => UIManager.Instance.OpenWindowAsync<FestivalActivityRechargeBaseWin>().Forget());
    }
    protected override void OnPreOpen()
Main/System/Horse/HorseController.cs
@@ -1,5 +1,6 @@
using System;
using Cysharp.Threading.Tasks;
using Spine.Unity;
using UnityEngine;
using UnityEngine.UI;
@@ -21,9 +22,10 @@
    // 创建坐骑 :id为0空坐骑也有配置
    //_skinID 坐骑的皮肤ID
    public void Create(int _skinID, int _heroSkinID = 0, float scale = 1f, Action _onComplete = null, string motionName = "idle")
    public async UniTask Create(int _skinID, int _heroSkinID = 0, float scale = 1f, Action _onComplete = null, string motionName = "idle")
    {
        pool = GameObjectPoolManager.Instance.GetPool(UILoader.LoadPrefab("UIHorse"));
        pool = GameObjectPoolManager.Instance.GetPool(await UILoader.LoadPrefabAsync("UIHorse"));
        if (this == null) return;
        if (instanceGO == null)
        {
            instanceGO = pool.Request();
@@ -43,7 +45,7 @@
            {
                skeletonGraphic.enabled = false;
            }
            CreateHero(_heroSkinID, scale);
            await CreateHero(_heroSkinID, scale);
            //避免重复创建
            return;
        }
@@ -66,11 +68,12 @@
            //卸下坐骑的情况
            skeletonGraphic.enabled = false;
            spineAnimationState = null;
            CreateHero(_heroSkinID, scale);
        await CreateHero(_heroSkinID, scale);
            return;
        }
        skeletonGraphic.skeletonDataAsset = ResManager.Instance.LoadAsset<SkeletonDataAsset>("UIEffect/Spine/Horse", skinConfig.Spine);
        skeletonGraphic.skeletonDataAsset = await ResManager.Instance.LoadAssetAsync<SkeletonDataAsset>("UIEffect/Spine/Horse", skinConfig.Spine);
        if (this == null) return;
        if (skeletonGraphic.skeletonDataAsset == null)
        {
@@ -93,12 +96,13 @@
        if (motionName == "")
            motionName = GetFistSpineAnim();
        PlayAnimation(motionName, true);
        CreateHero(_heroSkinID, scale);
        await CreateHero(_heroSkinID, scale);
        if (this == null) return;
        spineAnimationState.Complete -= OnAnimationComplete;
        spineAnimationState.Complete += OnAnimationComplete;
    }
    public void CreateHero(int heroSkinID, float _scale)
    public async UniTask CreateHero(int heroSkinID, float _scale)
    {
        if (instanceGO == null)
        {
@@ -123,8 +127,10 @@
            return;
        }
        hero.SetActive(true);
        hero.Create(heroSkinID, _scale);
        await hero.Create(heroSkinID, _scale);
        if (this == null) return;
        // 确保 BoneFollowerGraphic 引用到正确的坐骑 SkeletonGraphic
        var boneFollower = hero.GetComponent<BoneFollowerGraphic>();
        if (boneFollower != null && skeletonGraphic != null && skeletonGraphic.enabled)
Main/System/Main/HomeWin.cs
@@ -235,7 +235,7 @@
        });
        festivalActivityBtn.AddListener(() =>
        {
            UIManager.Instance.OpenWindow<FestivalActivityWin>();
            UIManager.Instance.OpenWindowAsync<FestivalActivityWin>().Forget();
        });
    }