三国卡牌客户端基础资源仓库
yyl
2025-05-19 2769f4c6422de2d85436b38ee7f5ad92236ed0cf
18 子 2D卡牌客户端搭建 / 2D卡牌客户端搭建
2个文件已修改
2 文件已重命名
1094 ■■■■ 已修改文件
Assets/Launch/Common/DownLoadAndDiscompressTask.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Launch/Launch.cs 60 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Launch/Manager/LocalResManager.cs 1028 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Launch/Manager/LocalResManager.cs.meta 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Launch/Common/DownLoadAndDiscompressTask.cs
@@ -73,8 +73,8 @@
            for (int i = 0; i < tasks.Count; i++)
            {
                var assetVersion = tasks[i];
                var remoteURL = StringUtility.Contact(ResManager.Instance.versionInfo.GetResourcesURL(VersionConfigEx.Get().branch), ResManager.fixPath, "/", assetVersion.relativePath);
                var localURL = StringUtility.Contact(ResManager.Instance.ExternalStorePath, assetVersion.relativePath);
                var remoteURL = StringUtility.Contact(LocalResManager.Instance.versionInfo.GetResourcesURL(VersionConfigEx.Get().branch), LocalResManager.fixPath, "/", assetVersion.relativePath);
                var localURL = StringUtility.Contact(ResourcesPath.Instance.ExternalStorePath, assetVersion.relativePath);
                DownloadMgr.Instance.AddTask(new DownloadTask(remoteURL, localURL));
            }
Assets/Launch/Launch.cs
@@ -80,21 +80,21 @@
        //内网下载测试
        _hotUpdateAss = System.AppDomain.CurrentDomain.GetAssemblies().First(a => a.GetName().Name == "Main");
        Type type = _hotUpdateAss.GetType("InGameDownTestUtility");
        ResManager.Instance.isPCTestDownLoad = (bool)type.GetMethod("GetReadVerionEx").Invoke(null, null);
        LocalResManager.Instance.isPCTestDownLoad = (bool)type.GetMethod("GetReadVerionEx").Invoke(null, null);
#endif
        SDKInit();
        ResManager.Instance.Init();
        ResManager.Instance.InitTable(() =>
        LocalResManager.Instance.Init();
        LocalResManager.Instance.InitTable(() =>
        {
            ResManager.Instance.InitDefaultLanguage();
            LocalResManager.Instance.InitDefaultLanguage();
            LaunchLoadingWin.OpenWindow();
            // ResManager.Instance.OpenWindow("LaunchExWin", m_UICanvas);
            // LocalResManager.Instance.OpenWindow("LaunchExWin", m_UICanvas);
#if !UNITY_EDITOR
            ResManager.step = ResManager.LoadDllStep.RequestVersion;
            LocalResManager.step = LocalResManager.LoadDllStep.RequestVersion;
#else
            if (ResManager.Instance.isPCTestDownLoad)
            if (LocalResManager.Instance.isPCTestDownLoad)
            {
                ResManager.step = ResManager.LoadDllStep.RequestVersion;
                LocalResManager.step = LocalResManager.LoadDllStep.RequestVersion;
            }
            else
            {
@@ -124,7 +124,7 @@
        if (_hotUpdateAss == null)
            _hotUpdateAss = System.AppDomain.CurrentDomain.GetAssemblies().First(a => a.GetName().Name == "Main");
#endif
        ResManager.step = ResManager.LoadDllStep.None;
        LocalResManager.step = LocalResManager.LoadDllStep.None;
        // m_UICanvas.gameObject.SetActive(false);
        DestroySingleton();
@@ -136,9 +136,9 @@
    private void DestroySingleton()
    {
        if (ResManager.IsValid())
        if (LocalResManager.IsValid())
        {
            ResManager.Destroy();
            LocalResManager.Destroy();
        }
        if (DownloadMgr.IsValid())
        {
@@ -165,32 +165,32 @@
    {
        if (stop)
            return;
        if (ResManager.step == ResManager.LoadDllStep.None || ResManager.step == ResManager.LoadDllStep.Wait)
        if (LocalResManager.step == LocalResManager.LoadDllStep.None || LocalResManager.step == LocalResManager.LoadDllStep.Wait)
            return;
        else if (ResManager.step == ResManager.LoadDllStep.RequestVersion)
        else if (LocalResManager.step == LocalResManager.LoadDllStep.RequestVersion)
        {
            ResManager.step = ResManager.LoadDllStep.Wait;
            ResManager.Instance.RequestVersionCheck();
            LocalResManager.step = LocalResManager.LoadDllStep.Wait;
            LocalResManager.Instance.RequestVersionCheck();
        }
        else if (ResManager.step == ResManager.LoadDllStep.PrepareDownLoad)
        else if (LocalResManager.step == LocalResManager.LoadDllStep.PrepareDownLoad)
        {
            ResManager.step = ResManager.LoadDllStep.Wait;
            LocalResManager.step = LocalResManager.LoadDllStep.Wait;
            //下载前准备,读表判断是否需要多语言不同下载路径
            PrepareDownLoad();
        }
        else if (ResManager.step == ResManager.LoadDllStep.DownLoad)
        else if (LocalResManager.step == LocalResManager.LoadDllStep.DownLoad)
        {
            ResManager.step = ResManager.LoadDllStep.Wait;
            LocalResManager.step = LocalResManager.LoadDllStep.Wait;
            BeginDownload();
        }
        else if (ResManager.step == ResManager.LoadDllStep.ReadBytes)
        else if (LocalResManager.step == LocalResManager.LoadDllStep.ReadBytes)
        {
            ResManager.step = ResManager.LoadDllStep.Wait;
            LocalResManager.step = LocalResManager.LoadDllStep.Wait;
            ReadDllBytes(this.StartGame);
        }
        //else if (ResManager.step == ResManager.LoadDllStep.Completed)
        //else if (LocalResManager.step == LocalResManager.LoadDllStep.Completed)
        //{
        //    ResManager.step = ResManager.LoadDllStep.None;
        //    LocalResManager.step = LocalResManager.LoadDllStep.None;
        //    m_UICanvas.gameObject.SetActive(false);
        //    DestroySingleton();
        //}
@@ -199,7 +199,7 @@
    private string GetWebRequestPath(string asset)
    {
        var path = ResManager.Instance.GetAssetFilePath(string.Concat(ResManager.bytesFolderName, asset));
        var path = LocalResManager.Instance.GetAssetFilePath(string.Concat(LocalResManager.bytesFolderName, asset));
        if (!path.Contains("file:"))
        {
@@ -211,7 +211,7 @@
    private async void ReadDllBytes(Action callback)
    {
        foreach (var assetVersion in ResManager.Instance.assetVersions.Values)
        foreach (var assetVersion in LocalResManager.Instance.assetVersions.Values)
        {
            if (assetVersion.localValid)
            {
@@ -265,16 +265,16 @@
    private void PrepareDownLoad()
    {
        ResManager.Instance.RequestLogicBytes();
        LocalResManager.Instance.RequestLogicBytes();
    }
    private void BeginDownload()
    {
        List<AssetVersion> priorDownLoadAssetVersions = new List<AssetVersion>();
        foreach (var assetVersion in ResManager.Instance.assetVersions.Values)
        foreach (var assetVersion in LocalResManager.Instance.assetVersions.Values)
        {
            AssetVersion localAssetVersion = null;
            ResManager.Instance.localAssetVersions.TryGetValue(assetVersion.relativePath, out localAssetVersion);
            LocalResManager.Instance.localAssetVersions.TryGetValue(assetVersion.relativePath, out localAssetVersion);
            if (!assetVersion.CheckLocalFileValid(localAssetVersion))
            {
                priorDownLoadAssetVersions.Add(assetVersion);
@@ -292,7 +292,7 @@
            DownloadComplete();
            return;
        }
        var targetDirectory = ResManager.Instance.ExternalStorePath;
        var targetDirectory = LocalResManager.Instance.ExternalStorePath;
        if (!Directory.Exists(targetDirectory))
        {
            Directory.CreateDirectory(targetDirectory);
@@ -303,7 +303,7 @@
    void DownloadComplete()
    {
        ResManager.step = ResManager.LoadDllStep.ReadBytes;
        LocalResManager.step = LocalResManager.LoadDllStep.ReadBytes;
    }
}
Assets/Launch/Manager/LocalResManager.cs
File was renamed from Assets/Launch/Manager/ResManager.cs
@@ -1,542 +1,488 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using System;
using UnityEngine.U2D;
using LitJson;
using System.IO;
using UnityEngine.Networking;
#if UNITY_EDITOR
using UnityEditor;
#endif
using LaunchCommon;
public class ResManager : Singleton<ResManager>
{
    //不下载时本地安卓测试路径
    public string assetBundlesPath = Application.dataPath + "/../AssetBundles/Android/";
    public static string bytesFolderName = "logicbytes/";
    public string StreamingAssetPath
    {
        get
        {
            return ResourcesPath.Instance.StreamingAssetPath;
        }
    }
    public string ExternalStorePath
    {
        get
        {
            return ResourcesPath.Instance.ExternalStorePath;
        }
    }
    //用于editor 下的资源路径
    public string ResourcesOutPath
    {
        get
        {
            return ResourcesPath.ResourcesOutPath;
        }
    }
    public string CONFIG_FODLER
    {
        get
        {
            return ResourcesPath.CONFIG_FODLER;
        }
    }
    public string ResourcesOutAssetPath
    {
        get
        {
            return ResourcesPath.ResourcesOutAssetPath;
        }
    }
    public bool isPCTestDownLoad = false;
    public static readonly string[] VERSION_URL = new string[] {
        "http://gamecenter.secondworld.net.cn:11000/center/appversion_new.php/?"};
    public int debugBranch { get; private set; }
    private int urlIndex = 0;
    private string versionUrl;
    public VersionInfo versionInfo { get; private set; }
    private static LoadDllStep m_step;
    public static LoadDllStep step
    {
        get { return m_step; }
        set
        {
            m_step = value;
            Debug.Log("LoadDllStep:" + m_step);
        }
    }
    string assetBytesUrl;
    //从网络获取的资源版本信息
    public Dictionary<string, AssetVersion> assetVersions = new Dictionary<string, AssetVersion>();
    //本地LogicBytes文件和 assetVersions 比较是否需要下载
    public Dictionary<string, AssetVersion> localAssetVersions = new Dictionary<string, AssetVersion>();
    public static string versionUrlResult { get; private set; }
    /// <summary>
    /// 语言的ID,用于区分下载资源
    /// </summary>
    /// <value></value>
    public static string Id
    {
        get
        {
            var config = InitialFunctionConfig.Get("Language").Numerical1;
            if (string.IsNullOrEmpty(config))
                return "";
            return LocalSave.GetString("LANGUAGE_ID1");
        }
        set
        {
            LocalSave.SetString("LANGUAGE_ID1", value);
        }
    }
    //默认路径不附加地址,Id不为空时附加Id
    public static string fixPath
    {
        get
        {
            if (string.IsNullOrEmpty(Id))
                return "";
            return string.Format("/{0}", Id);
        }
    }
    private AssetBundle spriteBundle = null;   //需要卸载
    private AssetBundle prefabBundle = null;   //需要卸载
    private SpriteAtlas spriteAtlas = null;
    public void Init()
    {
        if (LocalSave.GetString("#@#BrancH") != string.Empty)
        {
            int tmpbranch;
            int.TryParse(LocalSave.GetString("#@#BrancH").Substring(1), out tmpbranch);
            if (tmpbranch != 0)
                debugBranch = tmpbranch;
        }
        var parentDirectory = Directory.GetParent(Application.persistentDataPath);
        if (File.Exists(parentDirectory + "/Debug"))
        {
            var content = File.ReadAllText(parentDirectory + "/Debug");
            if (!string.IsNullOrEmpty(content))
            {
                var json = JsonMapper.ToObject<DebugBranch>(File.ReadAllText(parentDirectory + "/Debug"));
                debugBranch = json.branch;
            }
        }
        Clock.Init();
        Debug.Log("ResManager.Init");
    }
    public void Release()
    {
        spriteBundle?.Unload(true);  //true完全卸载,更新后重新加载
        prefabBundle?.Unload(true);
        assetVersions = null;
        localAssetVersions = null;
        spriteAtlas = null;
        Debug.Log("提前ResManager.Release资源");
    }
    public void RequestVersionCheck()
    {
        var versionConfig = VersionConfigEx.Get();
        var tables = new Dictionary<string, string>();
        tables["channel"] = versionConfig.appId;
        tables["versioncode"] = versionConfig.version;
        if (versionConfig.branch != 0)
        {
            tables["branch"] = versionConfig.branch.ToString();
        }
        tables["game"] = versionConfig.gameId;
        var url = string.Concat(VERSION_URL[urlIndex % VERSION_URL.Length], HttpRequest.HashtablaToString(tables));
        urlIndex++;
        versionUrl = url;
        Debug.Log("http地址:versionUrl  " + url);
        HttpRequest.Instance.RequestHttpGet(url, HttpRequest.defaultHttpContentType, 1, OnVersionCheckResult);
    }
    private void OnVersionCheckResult(bool _ok, string _result)
    {
        if (_ok)
        {
            versionUrlResult = _result.Replace("{}", "null");
            versionInfo = JsonMapper.ToObject<VersionInfo>(versionUrlResult);
            if (VersionConfigEx.Get().assetAccess == VersionConfigEx.InstalledAsset.IngoreDownLoad)
            {
                assetVersions = localAssetVersions;
                step = LoadDllStep.ReadBytes;
                return;
            }
            step = LoadDllStep.PrepareDownLoad;
        }
        else
        {
            Debug.Log("http 数据通讯: VersionUtility:" + versionUrl + "  result:" + versionUrlResult);
            Clock.AlarmAt(DateTime.Now + new TimeSpan(TimeSpan.TicksPerSecond), RequestVersionCheck);
        }
    }
    public string GetAssetFilePath(string _assetKey)
    {
        var path = Path.Combine(ExternalStorePath, _assetKey);
        if (!File.Exists(path))
        {
            path = Path.Combine(StreamingAssetPath, _assetKey);
        }
        return path;
    }
    public Sprite LoadSprite(string name)
    {
        Sprite sprite = null;
#if UNITY_EDITOR
        // if (excludePngs.Contains(StringUtility.Contact(name, ".png")))
        // {
        //     var path = StringUtility.Contact("Assets/ResourcesOut/BuiltIn/Sprites/", name, ".png");
        //     sprite = UnityEditor.AssetDatabase.LoadAssetAtPath<Sprite>(path);
        // }
        // else
        // {
            var spriteAtlas = UnityEditor.AssetDatabase.LoadAssetAtPath<SpriteAtlas>("Assets/ResourcesOut/BuiltIn/Sprites/sprites.spriteatlasv2");
            sprite = spriteAtlas.GetSprite(name);
        // }
#else
        if (spriteBundle == null)
        {
            string _path = GetAssetFilePath("builtin/sprites");
            spriteBundle = AssetBundle.LoadFromFile(_path);
        }
        sprite = spriteBundle.LoadAsset(name, typeof(Sprite)) as Sprite;
#endif
        if (sprite == null)
        {
            Debug.LogErrorFormat("LoadSprite() => 加载不到资源: {0}.", name);
        }
        return sprite;
    }
    public GameObject LoadBuiltInPrefab(string name)
    {
        GameObject prefab = null;
#if UNITY_EDITOR
        var path = string.Concat("Assets/ResourcesOut/BuiltIn/Prefabs/", name, ".prefab");
        prefab = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>(path);
#else
        if (prefabBundle == null)
        {
            string _path = GetAssetFilePath("builtin/prefabs");
            prefabBundle = AssetBundle.LoadFromFile(_path);
        }
        prefab = prefabBundle.LoadAsset(name) as GameObject;
#endif
        if (prefab == null)
        {
            Debug.LogErrorFormat("LoadBuiltInPrefab() => 加载不到资源: {0}.", name);
        }
        return prefab;
    }
    private string GetExtension(Type type)
    {
        if (type == typeof(GameObject))
            return ".prefab";
        else if (type == typeof(Sprite))
            return ".png";
        else if (type == typeof(Texture2D))
            return ".png";
        else if (type == typeof(Shader))
            return ".shader";
        else if (type == typeof(TextAsset))
            return ".txt";
        else if (type == typeof(AudioClip))
            return ".wav";
        else if (type == typeof(Font))
            return ".ttf";
        else if (type == typeof(Material))
            return ".mat";
        else
        {
            Debug.LogErrorFormat("GetExtension() => 不支持的资源类型: {0}.", type.Name);
            return "";
        }
    }
    public T LoadAsset<T> (string directory, string name) where T : UnityEngine.Object
    {
        T asset = null;
#if UNITY_EDITOR
        var path = string.Concat($"Assets/ResourcesOut/{directory}/{name}", GetExtension(typeof(T)));
        asset = UnityEditor.AssetDatabase.LoadAssetAtPath<T>(path);
#else
        if (prefabBundle == null)
        {
            // string _path = GetAssetFilePath("builtin/prefabs");
            string _path = GetAssetFilePath($"builtin/{directory}");
            prefabBundle = AssetBundle.LoadFromFile(_path);
        }
        asset = prefabBundle.LoadAsset(name) as t;
#endif
        if (asset == null)
        {
            Debug.LogErrorFormat("LoadBuiltInPrefab() => 加载不到资源: {0}.", name);
        }
        return asset;
    }
    public void InitDefaultLanguage()
    {
        var config = InitialFunctionConfig.Get("Language").Numerical1;
        Debug.LogFormat("系统语言:{0} {1}", Application.systemLanguage, config);
        if (string.IsNullOrEmpty(config))
            return;
        var id = LocalSave.GetString("LANGUAGE_ID1");
        if (!string.IsNullOrEmpty(id))
            return;
        switch (Application.systemLanguage)
        {
            case SystemLanguage.Chinese:
            case SystemLanguage.ChineseSimplified:
            case SystemLanguage.ChineseTraditional:
                {
                    id = "zh";
                    break;
                }
        }
        var json = JsonMapper.ToObject(config);
        if (json.Keys.Contains(id))
            Id = id;
        else
        {
            //开启的情况下必须要有个默认值
            Id = InitialFunctionConfig.Get("Language").Numerical2;
        }
    }
    //LogicBytes文件的MD5信息
    public void RequestLogicBytes()
    {
        var remoteURL = string.Concat(versionInfo.GetResourcesURL(VersionConfigEx.Get().branch), fixPath, "/logicbytes.txt");
        //var localURL = string.Concat(.ExternalStorePath, "/logicbytes.txt");
        assetBytesUrl = remoteURL;
        Debug.Log("http地址:logicbytesUrl  " + assetBytesUrl);
        //HttpRequest.Instance.RequestHttpGet(assetBytesUrl, HttpRequest.defaultHttpContentType, 3, OnGetAssetVersionFile);
        HttpRequest.Instance.UnityWebRequestGet(assetBytesUrl, 5, OnGetAssetVersionFile);
    }
    private void OnGetAssetVersionFile(bool _ok, string _result)
    {
        Debug.LogFormat("RequestLogicBytes文件结果:时间 {0},结果 {1}, 文件大小 {2}", DateTime.Now, _ok, _result.Length);
        if (_ok)
        {
            UpdateAssetVersions(_result);
            step = LoadDllStep.DownLoad;
        }
        else
        {
            Debug.Log("http 数据通讯: RequestLogicBytes:" + assetBytesUrl + "  result:" + _result);
            Clock.AlarmAt(DateTime.Now + new TimeSpan(TimeSpan.TicksPerSecond * 3), RequestLogicBytes);
        }
    }
    public Dictionary<string, AssetVersion> UpdateAssetVersions(string _assetVersionFile)
    {
        var lines = _assetVersionFile.Split(new string[] { FileExtersion.lineSplit }, StringSplitOptions.RemoveEmptyEntries);
        assetVersions.Clear();
        for (int i = 0; i < lines.Length; i++)
        {
            var assetVersion = new AssetVersion(lines[i]);
            assetVersions[assetVersion.relativePath] = assetVersion;
        }
        return assetVersions;
    }
    //读表 使用UnityWebRequest 考虑安卓环境
    private async UniTask ReadText(string table, Action<bool, string> OnComplete = null, string filePath = "")
    {
        var path = string.Empty;
        string content = string.Empty;
        bool result = false;
        if (filePath != "")
        {
            path = Path.Combine(filePath + $"{table}.txt");
        }
        else
        {
#if UNITY_EDITOR
            path = CONFIG_FODLER + $"/{table}.txt";
#else
        path = GetAssetFilePath($"config/{table}.txt");
#endif
        }
        if (!path.Contains("file:"))
        {
            //ExternalStorePath 路径需要添加
            path = "file://" + path;
        }
        Debug.LogFormat("ReadText() => path: {0}", path);
        UnityWebRequest www = UnityWebRequest.Get(path);
        await www.SendWebRequest();
#if UNITY_2020_1_OR_NEWER
    if (www.result != UnityWebRequest.Result.Success)
    {
        Debug.Log(www.error);
        OnComplete(result, content);
    }
#else
        if (www.isHttpError || www.isNetworkError)
        {
            Debug.Log(www.error);
            OnComplete(result, content);
        }
#endif
        else
        {
            content = www.downloadHandler.text;
            Debug.Log($"table:{table}  size:{content.Length}");
            result = true;
            OnComplete(result, content);
        }
    }
    public async void InitTable(Action OnComplete = null)
    {
        await ReadText("InitialFunction", (isOK, value) =>
        {
            if (isOK)
            {
                InitialFunctionConfig.Init(value);
                OnComplete();
            }
            else
            {
                Debug.LogError("InitTable InitialFunctionConfig error");
            }
        });
        if (isPCTestDownLoad || Application.isMobilePlatform)
        {
            //读取的一定是StreamingAssetPath路径
            await ReadText("logicbytes", (isOK, value) =>
            {
                if (isOK)
                    InitLocalLogicbytes(value);
                else
                    Debug.LogWarning("InitTable logicbytes error");
            }, StreamingAssetPath);
        }
    }
    //随包安装的资源不同平台不一定可以获取FileInfo,所以需要下载一个文件来获取资源的MD5信息
    //该文件在打包时生成 记录随包的所有资源的信息
    //该文件记录的资源在包中肯定存在,所以不用去取指定的资源文件获得FileInfo 计算MD5
    //随包LogicBytes文件的MD5信息 用于下载对比
    void InitLocalLogicbytes(string content)
    {
        using (StringReader reader = new StringReader(content))
        {
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                try
                {
                    var assetVersion = new AssetVersion(line);
                    assetVersion.localValid = true;
                    localAssetVersions[assetVersion.relativePath] = assetVersion;
                }
                catch (System.Exception ex)
                {
                    Debug.LogError(ex);
                }
            }
        }
    }
    public void UnloadAsset(string assetBundleName)
    {
    }
    public class VersionInfo
    {
        public JsonData notice_flag;
        public JsonData resource_url; //这里只用到这个取下载地址
        public string ResourceAward;
        public int downAsset = 1;
        public string downUrl;
        public int VersionCount;
        public string GetResourcesURL(int _branch)
        {
            if (resource_url != null)
            {
                return resource_url[_branch.ToString()].ToString();
            }
            else
            {
                return string.Empty;
            }
        }
    }
    public class DebugBranch
    {
        public int branch = -1;
    }
    public enum LoadDllStep
    {
        None,
        Wait,   //每个阶段的等待时间 比如在下载中就处于等待状态,完成后再进入下一个阶段
        RequestVersion,
        PrepareDownLoad,
        DownLoad,
        ReadBytes,
        Completed,
    }
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using System;
using UnityEngine.U2D;
using LitJson;
using System.IO;
using UnityEngine.Networking;
#if UNITY_EDITOR
using UnityEditor;
#endif
using LaunchCommon;
//  热更新前的代码
public class LocalResManager : Singleton<LocalResManager>
{
    //不下载时本地安卓测试路径
    public string assetBundlesPath = Application.dataPath + "/../AssetBundles/Android/";
    public static string bytesFolderName = "logicbytes/";
    public string StreamingAssetPath
    {
        get
        {
            return ResourcesPath.Instance.StreamingAssetPath;
        }
    }
    public string ExternalStorePath
    {
        get
        {
            return ResourcesPath.Instance.ExternalStorePath;
        }
    }
    //用于editor 下的资源路径
    public string ResourcesOutPath
    {
        get
        {
            return ResourcesPath.ResourcesOutPath;
        }
    }
    public string CONFIG_FODLER
    {
        get
        {
            return ResourcesPath.CONFIG_FODLER;
        }
    }
    public string ResourcesOutAssetPath
    {
        get
        {
            return ResourcesPath.ResourcesOutAssetPath;
        }
    }
    public bool isPCTestDownLoad = false;
    public static readonly string[] VERSION_URL = new string[] {
        "http://gamecenter.secondworld.net.cn:11000/center/appversion_new.php/?"};
    public int debugBranch { get; private set; }
    private int urlIndex = 0;
    private string versionUrl;
    public VersionInfo versionInfo { get; private set; }
    private static LoadDllStep m_step;
    public static LoadDllStep step
    {
        get { return m_step; }
        set
        {
            m_step = value;
            Debug.Log("LoadDllStep:" + m_step);
        }
    }
    string assetBytesUrl;
    //从网络获取的资源版本信息
    public Dictionary<string, AssetVersion> assetVersions = new Dictionary<string, AssetVersion>();
    //本地LogicBytes文件和 assetVersions 比较是否需要下载
    public Dictionary<string, AssetVersion> localAssetVersions = new Dictionary<string, AssetVersion>();
    public static string versionUrlResult { get; private set; }
        /// <summary>
    /// 语言的ID,用于区分下载资源
    /// </summary>
    /// <value></value>
    public static string Id
    {
        get
        {
            var config = InitialFunctionConfig.Get("Language").Numerical1;
            if (string.IsNullOrEmpty(config))
                return "";
            return LocalSave.GetString("LANGUAGE_ID1");
        }
        set
        {
            LocalSave.SetString("LANGUAGE_ID1", value);
        }
    }
    //默认路径不附加地址,Id不为空时附加Id
    public static string fixPath
    {
        get
        {
            if (string.IsNullOrEmpty(Id))
                return "";
            return string.Format("/{0}", Id);
        }
    }
    private AssetBundle spriteBundle = null;   //需要卸载
    private AssetBundle prefabBundle = null;   //需要卸载
    private SpriteAtlas spriteAtlas = null;
    public void Init()
    {
        if (LocalSave.GetString("#@#BrancH") != string.Empty)
        {
            int tmpbranch;
            int.TryParse(LocalSave.GetString("#@#BrancH").Substring(1), out tmpbranch);
            if (tmpbranch != 0)
                debugBranch = tmpbranch;
        }
        var parentDirectory = Directory.GetParent(Application.persistentDataPath);
        if (File.Exists(parentDirectory + "/Debug"))
        {
            var content = File.ReadAllText(parentDirectory + "/Debug");
            if (!string.IsNullOrEmpty(content))
            {
                var json = JsonMapper.ToObject<DebugBranch>(File.ReadAllText(parentDirectory + "/Debug"));
                debugBranch = json.branch;
            }
        }
        Clock.Init();
        Debug.Log("LocalResManager.Init");
    }
    public void Release()
    {
        spriteBundle?.Unload(true);  //true完全卸载,更新后重新加载
        prefabBundle?.Unload(true);
        assetVersions = null;
        localAssetVersions = null;
        spriteAtlas = null;
        Debug.Log("提前ResManager.Release资源");
    }
    public void RequestVersionCheck()
    {
        var versionConfig = VersionConfigEx.Get();
        var tables = new Dictionary<string, string>();
        tables["channel"] = versionConfig.appId;
        tables["versioncode"] = versionConfig.version;
        if (versionConfig.branch != 0)
        {
            tables["branch"] = versionConfig.branch.ToString();
        }
        tables["game"] = versionConfig.gameId;
        var url = string.Concat(VERSION_URL[urlIndex % VERSION_URL.Length], HttpRequest.HashtablaToString(tables));
        urlIndex++;
        versionUrl = url;
        Debug.Log("http地址:versionUrl  " + url);
        HttpRequest.Instance.RequestHttpGet(url, HttpRequest.defaultHttpContentType, 1, OnVersionCheckResult);
    }
    private void OnVersionCheckResult(bool _ok, string _result)
    {
        if (_ok)
        {
            versionUrlResult = _result.Replace("{}", "null");
            versionInfo = JsonMapper.ToObject<VersionInfo>(versionUrlResult);
            if (VersionConfigEx.Get().assetAccess == VersionConfigEx.InstalledAsset.IngoreDownLoad)
            {
                assetVersions = localAssetVersions;
                step = LoadDllStep.ReadBytes;
                return;
            }
            step = LoadDllStep.PrepareDownLoad;
        }
        else
        {
            Debug.Log("http 数据通讯: VersionUtility:" + versionUrl + "  result:" + versionUrlResult);
            Clock.AlarmAt(DateTime.Now + new TimeSpan(TimeSpan.TicksPerSecond), RequestVersionCheck);
        }
    }
    public string GetAssetFilePath(string _assetKey)
    {
        var path = Path.Combine(ExternalStorePath, _assetKey);
        if (!File.Exists(path))
        {
            path = Path.Combine(StreamingAssetPath, _assetKey);
        }
        return path;
    }
    public Sprite LoadSprite(string name)
    {
        Sprite sprite = null;
#if UNITY_EDITOR
        // if (excludePngs.Contains(StringUtility.Contact(name, ".png")))
        // {
        //     var path = StringUtility.Contact("Assets/ResourcesOut/BuiltIn/Sprites/", name, ".png");
        //     sprite = UnityEditor.AssetDatabase.LoadAssetAtPath<Sprite>(path);
        // }
        // else
        // {
            var spriteAtlas = UnityEditor.AssetDatabase.LoadAssetAtPath<SpriteAtlas>("Assets/ResourcesOut/BuiltIn/Sprites/sprites.spriteatlasv2");
            sprite = spriteAtlas.GetSprite(name);
        // }
#else
        if (spriteBundle == null)
        {
            string _path = GetAssetFilePath("builtin/sprites");
            spriteBundle = AssetBundle.LoadFromFile(_path);
        }
        sprite = spriteBundle.LoadAsset(name, typeof(Sprite)) as Sprite;
#endif
        if (sprite == null)
        {
            Debug.LogErrorFormat("LoadSprite() => 加载不到资源: {0}.", name);
        }
        return sprite;
    }
    public GameObject LoadBuiltInPrefab(string name)
    {
        GameObject prefab = null;
#if UNITY_EDITOR
        var path = string.Concat("Assets/ResourcesOut/BuiltIn/Prefabs/", name, ".prefab");
        prefab = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>(path);
#else
        if (prefabBundle == null)
        {
            string _path = GetAssetFilePath("builtin/prefabs");
            prefabBundle = AssetBundle.LoadFromFile(_path);
        }
        prefab = prefabBundle.LoadAsset(name) as GameObject;
#endif
        if (prefab == null)
        {
            Debug.LogErrorFormat("LoadBuiltInPrefab() => 加载不到资源: {0}.", name);
        }
        return prefab;
    }
    public void InitDefaultLanguage()
    {
        var config = InitialFunctionConfig.Get("Language").Numerical1;
        Debug.LogFormat("系统语言:{0} {1}", Application.systemLanguage, config);
        if (string.IsNullOrEmpty(config))
            return;
        var id = LocalSave.GetString("LANGUAGE_ID1");
        if (!string.IsNullOrEmpty(id))
            return;
        switch (Application.systemLanguage)
        {
            case SystemLanguage.Chinese:
            case SystemLanguage.ChineseSimplified:
            case SystemLanguage.ChineseTraditional:
                {
                    id = "zh";
                    break;
                }
        }
        var json = JsonMapper.ToObject(config);
        if (json.Keys.Contains(id))
            Id = id;
        else
        {
            //开启的情况下必须要有个默认值
            Id = InitialFunctionConfig.Get("Language").Numerical2;
        }
    }
    //LogicBytes文件的MD5信息
    public void RequestLogicBytes()
    {
        var remoteURL = string.Concat(versionInfo.GetResourcesURL(VersionConfigEx.Get().branch), fixPath, "/logicbytes.txt");
        //var localURL = string.Concat(.ExternalStorePath, "/logicbytes.txt");
        assetBytesUrl = remoteURL;
        Debug.Log("http地址:logicbytesUrl  " + assetBytesUrl);
        //HttpRequest.Instance.RequestHttpGet(assetBytesUrl, HttpRequest.defaultHttpContentType, 3, OnGetAssetVersionFile);
        HttpRequest.Instance.UnityWebRequestGet(assetBytesUrl, 5, OnGetAssetVersionFile);
    }
    private void OnGetAssetVersionFile(bool _ok, string _result)
    {
        Debug.LogFormat("RequestLogicBytes文件结果:时间 {0},结果 {1}, 文件大小 {2}", DateTime.Now, _ok, _result.Length);
        if (_ok)
        {
            UpdateAssetVersions(_result);
            step = LoadDllStep.DownLoad;
        }
        else
        {
            Debug.Log("http 数据通讯: RequestLogicBytes:" + assetBytesUrl + "  result:" + _result);
            Clock.AlarmAt(DateTime.Now + new TimeSpan(TimeSpan.TicksPerSecond * 3), RequestLogicBytes);
        }
    }
    public Dictionary<string, AssetVersion> UpdateAssetVersions(string _assetVersionFile)
    {
        var lines = _assetVersionFile.Split(new string[] { FileExtersion.lineSplit }, StringSplitOptions.RemoveEmptyEntries);
        assetVersions.Clear();
        for (int i = 0; i < lines.Length; i++)
        {
            var assetVersion = new AssetVersion(lines[i]);
            assetVersions[assetVersion.relativePath] = assetVersion;
        }
        return assetVersions;
    }
    //读表 使用UnityWebRequest 考虑安卓环境
    private async UniTask ReadText(string table, Action<bool, string> OnComplete = null, string filePath = "")
    {
        var path = string.Empty;
        string content = string.Empty;
        bool result = false;
        if (filePath != "")
        {
            path = Path.Combine(filePath + $"{table}.txt");
        }
        else
        {
#if UNITY_EDITOR
            path = CONFIG_FODLER + $"/{table}.txt";
#else
        path = GetAssetFilePath($"config/{table}.txt");
#endif
        }
        if (!path.Contains("file:"))
        {
            //ExternalStorePath 路径需要添加
            path = "file://" + path;
        }
        Debug.LogFormat("ReadText() => path: {0}", path);
        UnityWebRequest www = UnityWebRequest.Get(path);
        await www.SendWebRequest();
#if UNITY_2020_1_OR_NEWER
    if (www.result != UnityWebRequest.Result.Success)
    {
        Debug.Log(www.error);
        OnComplete(result, content);
    }
#else
        if (www.isHttpError || www.isNetworkError)
        {
            Debug.Log(www.error);
            OnComplete(result, content);
        }
#endif
        else
        {
            content = www.downloadHandler.text;
            Debug.Log($"table:{table}  size:{content.Length}");
            result = true;
            OnComplete(result, content);
        }
    }
    public async void InitTable(Action OnComplete = null)
    {
        await ReadText("InitialFunction", (isOK, value) =>
        {
            if (isOK)
            {
                InitialFunctionConfig.Init(value);
                OnComplete();
            }
            else
            {
                Debug.LogError("InitTable InitialFunctionConfig error");
            }
        });
        if (isPCTestDownLoad || Application.isMobilePlatform)
        {
            //读取的一定是StreamingAssetPath路径
            await ReadText("logicbytes", (isOK, value) =>
            {
                if (isOK)
                    InitLocalLogicbytes(value);
                else
                    Debug.LogWarning("InitTable logicbytes error");
            }, StreamingAssetPath);
        }
    }
    //随包安装的资源不同平台不一定可以获取FileInfo,所以需要下载一个文件来获取资源的MD5信息
    //该文件在打包时生成 记录随包的所有资源的信息
    //该文件记录的资源在包中肯定存在,所以不用去取指定的资源文件获得FileInfo 计算MD5
    //随包LogicBytes文件的MD5信息 用于下载对比
    void InitLocalLogicbytes(string content)
    {
        using (StringReader reader = new StringReader(content))
        {
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                try
                {
                    var assetVersion = new AssetVersion(line);
                    assetVersion.localValid = true;
                    localAssetVersions[assetVersion.relativePath] = assetVersion;
                }
                catch (System.Exception ex)
                {
                    Debug.LogError(ex);
                }
            }
        }
    }
    public class VersionInfo
    {
        public JsonData notice_flag;
        public JsonData resource_url; //这里只用到这个取下载地址
        public string ResourceAward;
        public int downAsset = 1;
        public string downUrl;
        public int VersionCount;
        public string GetResourcesURL(int _branch)
        {
            if (resource_url != null)
            {
                return resource_url[_branch.ToString()].ToString();
            }
            else
            {
                return string.Empty;
            }
        }
    }
    public class DebugBranch
    {
        public int branch = -1;
    }
    public enum LoadDllStep
    {
        None,
        Wait,   //每个阶段的等待时间 比如在下载中就处于等待状态,完成后再进入下一个阶段
        RequestVersion,
        PrepareDownLoad,
        DownLoad,
        ReadBytes,
        Completed,
    }
}
Assets/Launch/Manager/LocalResManager.cs.meta
File was renamed from Assets/Launch/Manager/ResManager.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 48ce53db3d9aea84aaf3155c8a41caa4
guid: 22fb6d897728ace438ffbae7628b8e07
MonoImporter:
  externalObjects: {}
  serializedVersion: 2