三国卡牌客户端基础资源仓库
0312 打包的时候每次拷贝一份最新的InitialFunction.txt
热更部分的语言设置值取自非热更逻辑设置的值
增加多次请求InitialFunction.txt
5个文件已修改
1个文件已添加
211 ■■■■ 已修改文件
Assets/Editor/Tool/ClientPackage.cs 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Launch/Config/InitialFunctionConfig.cs 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Launch/Launch.cs 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Launch/Manager/LocalResManager.cs 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Launch/UI/LaunchWins/LaunchExWin.cs 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Resources/Config.meta 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/Tool/ClientPackage.cs
@@ -835,6 +835,27 @@
        }
        File.WriteAllText(versionConfigExFile, json);
        // 拷贝 InitialFunction.txt 到 Resources/Config,确保构建时同步最新配置
        string initialFuncSource = Application.dataPath + "/ResourcesOut/Config/InitialFunction.txt";
        string initialFuncDestDir = Application.dataPath + "/Resources/Config";
        string initialFuncDest = initialFuncDestDir + "/InitialFunction.txt";
        if (File.Exists(initialFuncSource))
        {
            if (!Directory.Exists(initialFuncDestDir))
            {
                Directory.CreateDirectory(initialFuncDestDir);
            }
            if (File.Exists(initialFuncDest))
            {
                File.Delete(initialFuncDest);
            }
            File.Copy(initialFuncSource, initialFuncDest);
            Debug.Log($"[ClientPackage] InitialFunction.txt 已同步到 Resources/Config");
        }
        else
        {
            Debug.LogWarning($"[ClientPackage] InitialFunction.txt 源文件不存在: {initialFuncSource}");
        }
        SetIconAndSplashImage(versionName);
        //SetCreateRoleAnimation();
Assets/Launch/Config/InitialFunctionConfig.cs
@@ -11,7 +11,7 @@
namespace LaunchCommon
{
    public class InitialFunctionConfig
    public class InitialFunctionConfigEx
    {
        public readonly string KEY;
@@ -21,11 +21,11 @@
        public readonly string Numerical4;
        public readonly string Numerical5;
        public InitialFunctionConfig()
        public InitialFunctionConfigEx()
        {
        }
        public InitialFunctionConfig(string input)
        public InitialFunctionConfigEx(string input)
        {
            try
            {
@@ -49,8 +49,8 @@
            }
        }
        static Dictionary<string, InitialFunctionConfig> configs = new Dictionary<string, InitialFunctionConfig>();
        public static InitialFunctionConfig Get(string id)
        static Dictionary<string, InitialFunctionConfigEx> configs = new Dictionary<string, InitialFunctionConfigEx>();
        public static InitialFunctionConfigEx Get(string id)
        {
            if (!inited)
            {
@@ -63,17 +63,17 @@
                return configs[id];
            }
            InitialFunctionConfig config = null;
            InitialFunctionConfigEx config = null;
            if (rawDatas.ContainsKey(id))
            {
                config = configs[id] = new InitialFunctionConfig(rawDatas[id]);
                config = configs[id] = new InitialFunctionConfigEx(rawDatas[id]);
                rawDatas.Remove(id);
            }
            return config;
        }
        public static InitialFunctionConfig Get(int id)
        public static InitialFunctionConfigEx Get(int id)
        {
            return Get(id.ToString());
        }
@@ -86,9 +86,9 @@
            return keys;
        }
        public static List<InitialFunctionConfig> GetValues()
        public static List<InitialFunctionConfigEx> GetValues()
        {
            var values = new List<InitialFunctionConfig>();
            var values = new List<InitialFunctionConfigEx>();
            values.AddRange(configs.Values);
            var keys = new List<string>(rawDatas.Keys);
Assets/Launch/Launch.cs
@@ -159,7 +159,7 @@
            {
                playMode = EPlayMode.HostPlayMode;
                remoteCdnBaseUrl = cdnUrl;
                Debug.Log($"[Launch] cdnUrl={cdnUrl}, using HostPlayMode");
                // Debug.Log($"[Launch] cdnUrl={cdnUrl}, using HostPlayMode");
            }
            else
            {
@@ -168,7 +168,7 @@
            }
#endif
            Debug.Log($"[Launch] Initializing YooAsset early with PlayMode={playMode}");
            Debug.Log($"[Launch] cdnUrl={remoteCdnBaseUrl+ LocalResManager.fixPath}, PlayMode={playMode}");
            await YooAssetInitializer.Instance.InitializeAsync(playMode, remoteServices, remoteCdnBaseUrl + LocalResManager.fixPath);
#if UNITY_WEBGL
@@ -223,7 +223,7 @@
    }
    /// <summary>
    /// YooAsset 就绪后显示加载界面(由 OnVersionCheckResult → InitTable 回调调用)
    /// YooAsset 就绪后显示加载界面
    /// </summary>
    public void ShowLaunchUI()
    {
@@ -305,11 +305,11 @@
    private void DestroySingleton()
    {
        if (LocalResManager.IsValid())
        {
            LocalResManager.Instance.Release();
            LocalResManager.Destroy();
        }
        // if (LocalResManager.IsValid())
        // {
        //     LocalResManager.Instance.Release();
        //     LocalResManager.Destroy();
        // }
        if (LogicEngine.IsValid())
        {
Assets/Launch/Manager/LocalResManager.cs
@@ -385,14 +385,22 @@
    private async UniTaskVoid LoadInitialFunctionAndStartAsync(string initFuncUrl)
    {
        //默认要保证保底测试正确,后续可以在编辑器下增加个开关,来决定是否从CDN读取配置测试
        //打包时会默认拷贝InitialFunction.txt到 Resources/Config/InitialFunction.txt
#if UNITY_EDITOR
        await TryLoadInitialFunctionFromResourcesAsync();
#else
        bool configReady = await TryLoadInitialFunctionFromCdnAsync(initFuncUrl);
        if (!configReady)
        {
            await TryLoadInitialFunctionFromResourcesAsync();
            await InitializeYooAssetAndEnterReadBytesAsync();
        }
#endif
        await InitializeYooAssetAndEnterReadBytesAsync();
    }
    private const int INIT_FUNC_MAX_RETRY = 5;
    private const float INIT_FUNC_RETRY_DELAY_SEC = 1f;
    private async UniTask<bool> TryLoadInitialFunctionFromCdnAsync(string initFuncUrl)
    {
@@ -402,31 +410,44 @@
            return false;
        }
        var response = await HttpRequest.Instance.UnityWebRequestGetAsync(initFuncUrl, HttpRequest.defaultHttpContentType, 10);
        if (!response.ok)
        for (int i = 0; i <= INIT_FUNC_MAX_RETRY; i++)
        {
            Debug.LogWarning($"[LocalResManager] 从 CDN 加载 InitialFunction.txt 失败,url={initFuncUrl},error={response.message}");
            return false;
            if (i > 0)
            {
                Debug.LogWarning($"[LocalResManager] 重试加载 InitialFunction.txt 第 {i}/{INIT_FUNC_MAX_RETRY} 次...");
                await UniTask.Delay(TimeSpan.FromSeconds(INIT_FUNC_RETRY_DELAY_SEC));
            }
            var response = await HttpRequest.Instance.UnityWebRequestGetAsync(initFuncUrl, HttpRequest.defaultHttpContentType, 10);
            if (!response.ok)
            {
                Debug.LogWarning($"[LocalResManager] 从 CDN 加载 InitialFunction.txt 失败(第 {i + 1} 次),url={initFuncUrl},error={response.message}");
                continue;
            }
            if (string.IsNullOrEmpty(response.message))
            {
                Debug.LogWarning($"[LocalResManager] CDN InitialFunction.txt 内容为空(第 {i + 1} 次),url={initFuncUrl}");
                continue;
            }
            try
            {
                InitialFunctionConfigEx.Init(response.message);
                // 需要根据languagefix 重新把cdn地址转向正确的多语言版本的cdn地址
                InitDefaultLanguage();
                Debug.Log($"[LocalResManager] 成功加载 CDN InitialFunction.txt(第 {i + 1} 次尝试)");
                return true;
            }
            catch (Exception ex)
            {
                Debug.LogError($"[LocalResManager] 解析 CDN InitialFunction.txt 失败(第 {i + 1} 次),url={initFuncUrl},error={ex}");
                continue;
            }
        }
        if (string.IsNullOrEmpty(response.message))
        {
            Debug.LogWarning($"[LocalResManager] CDN InitialFunction.txt 内容为空,url={initFuncUrl}");
            return false;
        }
        try
        {
            InitialFunctionConfig.Init(response.message);
            // 需要根据languagefix 重新把cdn地址转向正确的多语言版本的cdn地址
            InitDefaultLanguage();
            return true;
        }
        catch (Exception ex)
        {
            Debug.LogError($"[LocalResManager] 解析 CDN InitialFunction.txt 失败,url={initFuncUrl},error={ex}");
            return false;
        }
        Debug.LogError($"[LocalResManager] 重试 {INIT_FUNC_MAX_RETRY + 1} 次后仍无法加载 InitialFunction.txt");
        return false;
    }
    private async UniTask<bool> TryLoadInitialFunctionFromResourcesAsync()
@@ -440,7 +461,7 @@
                return false;
            }
            InitialFunctionConfig.Init(textAsset.text);
            InitialFunctionConfigEx.Init(textAsset.text);
            // 需要根据languagefix 重新把cdn地址转向正确的多语言版本的cdn地址
            InitDefaultLanguage();
            Debug.Log("[LocalResManager] 已使用包内 InitialFunction.txt 初始化启动配置。");
@@ -630,11 +651,11 @@
    public void InitDefaultLanguage()
    {
        //初始化, 该表是随包安装的如果热更需要二次才生效
        if (!InitialFunctionConfig.Has("LanguageEx"))
        if (!InitialFunctionConfigEx.Has("LanguageEx"))
        {
            return;
        }
        var config = InitialFunctionConfig.Get("LanguageEx");
        var config = InitialFunctionConfigEx.Get("LanguageEx");
        if (config.Numerical1 == null || config.Numerical2 == null || config.Numerical3 == null)
        {
            return;
@@ -694,59 +715,6 @@
        Debug.LogFormat("系统语言:{0} 设置为{1}", Application.systemLanguage, Id);
    }
    // 通过 YooAsset 加载 TextAsset 类型的文本文件。
    // location: 完整的 YooAsset 路径,如 "Assets/ResourcesOut/Config/InitialFunction.txt"
    // Editor 下直接读物理文件(剥离 Assets/ 前缀后拼 Application.dataPath)
    private async UniTask ReadText(string fileName, Action<bool, string> OnComplete = null)
    {
        string content = string.Empty;
        bool result = false;
        string path = "Config/" + fileName;
        TextAsset textAsset = await Resources.LoadAsync<TextAsset>(path) as TextAsset; // 预热资源,避免后续首次加载时的额外延迟
        if (textAsset != null)
        {
            content = textAsset.text;
            result = true;
        }
        else
        {
            Debug.LogError("LoadResourceFailure " + path);
        }
        OnComplete?.Invoke(result, content);
    }
    /// <summary>
    /// 初始化配置表。
    /// 通过 YooAsset 加载 InitialFunction 配置(调用前需确保 YooAsset 已初始化)。
    /// </summary>
    public async UniTask InitTable(Action OnComplete = null)
    {
        if (null == VersionConfigEx.config)
        {
#if UNITY_WEBGL
            await VersionConfigEx.Get();
#else
            VersionConfigEx.Get();
#endif
        }
        await ReadText("InitialFunction", (isOK, value) =>
        {
            if (isOK)
            {
                InitialFunctionConfig.Init(value);
                OnComplete();
            }
            else
            {
                Debug.LogError("InitTable InitialFunctionConfig error");
            }
        });
    }
    #region 事件汇报
#if TEST_URL
@@ -760,9 +728,9 @@
    {
        //默认发送即使表没有初始化
        if (InitialFunctionConfig.inited)
        if (InitialFunctionConfigEx.inited)
        {
            var config = InitialFunctionConfig.Get("Event");
            var config = InitialFunctionConfigEx.Get("Event");
            if (config != null && config.Numerical1 != "1")
            {
                return;
Assets/Launch/UI/LaunchWins/LaunchExWin.cs
@@ -4,6 +4,7 @@
using UnityEngine.UI;
using Cysharp.Threading.Tasks;
using LaunchCommon;
using LitJson;
public class LaunchExWin : MonoBehaviour
{
@@ -41,7 +42,9 @@
    /// </summary>
    public async UniTask InitSpritesAsync()
    {
        sliderText = InitialFunctionConfig.Get("Language").Numerical3;
        var languageShowDict = JsonMapper.ToObject<Dictionary<string, string>>(InitialFunctionConfigEx.Get("Language").Numerical1);
        var id = string.IsNullOrEmpty(LocalResManager.Id) ? "zh" : LocalResManager.Id;  // 默认中文
        sliderText = languageShowDict[id];
        var sprites = await UniTask.WhenAll(
            LocalResManager.Instance.LoadSpriteAsync("TY_TB_JH1"),
            LocalResManager.Instance.LoadSpriteAsync("TY_TB_JH2"),
@@ -64,9 +67,12 @@
        {
            m_NetworkContainer.gameObject.SetActive(false);
        }
        m_NetworkTip.text = InitialFunctionConfig.Get("Language").Numerical4;
        var AppleCheck = InitialFunctionConfig.Get("CheckTime").Numerical1;
        var languageShowDict = JsonMapper.ToObject<Dictionary<string, string>>(InitialFunctionConfigEx.Get("Language").Numerical2);
        var id = string.IsNullOrEmpty(LocalResManager.Id) ? "zh" : LocalResManager.Id;  // 默认中文
        m_NetworkTip.text = languageShowDict[id];
        var AppleCheck = InitialFunctionConfigEx.Get("CheckTime").Numerical1;
        if (Application.platform == RuntimePlatform.IPhonePlayer && AppleCheck == "1")
            ShowCircleView = true;
@@ -85,7 +91,7 @@
            var config = VersionConfigEx.config;
                m_Version.text = StringUtility.Concat(config.version, "_", config.buildIndex.ToString(),
                    "_", InitialFunctionConfig.Get("version").Numerical1, " ", LocalResManager.Id);
                    "_", InitialFunctionConfigEx.Get("version").Numerical1, " ", LocalResManager.Id);
            // m_Version.text = StringUtility.Concat(VersionConfigEx.Get().version, "_", VersionConfigEx.Get().buildIndex.ToString(),
            //     "_", InitialFunctionConfig.Get("version").Numerical1, " ", LocalResManager.Id);
Assets/Resources/Config.meta
New file
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 036bbe531c188f144b05ad192d761a05
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant: