| using UnityEngine;  | 
| using System;  | 
| using System.IO;  | 
| using System.Collections.Generic;  | 
| using LitJsonForAot;  | 
| using System.Collections;  | 
| using UnityEngine.Networking;  | 
|   | 
|   | 
| namespace StartAot  | 
| {  | 
|     public class ResourcesModel : SingletonMonobehaviour<ResourcesModel>  | 
|     {  | 
|         //不下载时本地安卓测试路径  | 
|         public string assetBundlesPath { get; private set; }  | 
|         public static string bytesFolderName = "logicbytes/";  | 
|         public string StreamingAssetPath { get; private set; }  | 
|         public string ExternalStorePath { get; private set; }  | 
|   | 
|         //用于editor 下的资源路径  | 
|         public string ResourcesOutPath { get; private set; }  | 
|         public string CONFIG_FODLER { get; private set; }  | 
|         public const string ResourcesOutAssetPath = "Assets/ResourcesOut/";  | 
|   | 
|         public bool isPCTestDownLoad = false;  | 
|   | 
|         public static readonly string[] VERSION_URL = new string[] {  | 
|         "http://yncenter.secondworld.net.cn:11000/center/appversion_new.php/?"};  | 
|   | 
|   | 
|         public int debugBranch { get; private set; }  | 
|   | 
|         public class DebugBranch  | 
|         {  | 
|             public int branch = -1;  | 
|         }  | 
|   | 
|         private int urlIndex = 0;  | 
|         private string versionUrl;  | 
|         public VersionInfo versionInfo { get; private set; }  | 
|   | 
|         public enum LoadDllStep  | 
|         {  | 
|             None,  | 
|             Wait,   //每个阶段的等待时间 比如在下载中就处于等待状态,完成后再进入下一个阶段  | 
|             RequestVersion,  | 
|             PrepareDownLoad,  | 
|             DownLoad,  | 
|             ReadBytes,  | 
|             Completed,  | 
|         }  | 
|   | 
|         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);  | 
|             }  | 
|         }  | 
|   | 
|   | 
|         AssetBundle spriteBundle = null;   //需要卸载  | 
|         AssetBundle prefabBundle = null;   //需要卸载  | 
|         public void Init()  | 
|         {  | 
|             if (Application.isMobilePlatform)  | 
|             {  | 
|                 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("ResourcesModel.Init");  | 
|         }  | 
|   | 
|         void Awake()  | 
|         {  | 
| #if UNITY_ANDROID  | 
|             StreamingAssetPath = Application.streamingAssetsPath + "/android/";  | 
| #elif UNITY_IOS  | 
|         StreamingAssetPath = Application.streamingAssetsPath + "/ios/";  | 
| #else  | 
|         StreamingAssetPath = Application.streamingAssetsPath + "/standalone/";  | 
| #endif  | 
|   | 
|             if (!Application.isEditor)  | 
|             {  | 
|                 switch (Application.platform)  | 
|                 {  | 
|                     case RuntimePlatform.WindowsPlayer:  | 
|                         ExternalStorePath = Path.GetDirectoryName(Application.streamingAssetsPath) + "/ExternalAssets/";  | 
|                         break;  | 
|                     default:  | 
|                         ExternalStorePath = Application.persistentDataPath + "/";  | 
|                         break;  | 
|                 }  | 
|             }  | 
|             else  | 
|             {  | 
|                 ExternalStorePath = Application.persistentDataPath + "/";  | 
|             }  | 
|             assetBundlesPath = Application.dataPath + "/../AssetBundles/Android/";  | 
|             ResourcesOutPath = Application.dataPath + "/ResourcesOut/";  | 
|             CONFIG_FODLER = ResourcesOutPath + "refdata/Config";  | 
|             Debug.Log("ResourcesModel 路径初始化");  | 
|         }  | 
|   | 
|         //显示调用卸载资源  | 
|         public void Destroy()  | 
|         {  | 
|             spriteBundle?.Unload(true);  //true完全卸载,更新后重新加载  | 
|             prefabBundle?.Unload(true);  | 
|             assetVersions.Clear();  | 
|             localAssetVersions.Clear();  | 
|             Debug.Log("提前ResourcesModel.Destroy资源");  | 
|         }  | 
|   | 
|   | 
|         public void RequestVersionCheck()  | 
|         {  | 
|             var versionConfig = VersionConfigEx.Get();  | 
|   | 
|             if (versionConfig.assetAccess == VersionConfigEx.InstalledAsset.IngoreDownLoad)  | 
|             {  | 
|                 step = LoadDllStep.ReadBytes;  | 
|                 return;  | 
|             }  | 
|             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 % 2], 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);  | 
|                 step = LoadDllStep.PrepareDownLoad;  | 
|             }  | 
|             else  | 
|             {  | 
|                 Debug.Log("http 数据通讯: VersionUtility:" + versionUrl + "  result:" + versionUrlResult);  | 
|                 Clock.AlarmAt(DateTime.Now + new TimeSpan(TimeSpan.TicksPerSecond), RequestVersionCheck);  | 
|             }  | 
|         }  | 
|   | 
|         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 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  | 
|             var path = StringUtility.Contact("Assets/ResourcesOut/BuiltIn/Sprites/", name, ".png");  | 
|             sprite = UnityEditor.AssetDatabase.LoadAssetAtPath<Sprite>(path);  | 
|   | 
| #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)  | 
|             {  | 
|                 DebugEx.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)  | 
|             {  | 
|                 DebugEx.LogErrorFormat("LoadBuiltInPrefab() => 加载不到资源: {0}.", name);  | 
|             }  | 
|   | 
|             return prefab;  | 
|         }  | 
|   | 
|         public void OpenWindow(string windowName, Transform parent)  | 
|         {  | 
|             GameObject window = GameObject.Instantiate(LoadBuiltInPrefab(windowName));  | 
|             window.transform.SetParent(parent);  | 
|             window.transform.localScale = Vector3.one;  | 
|             (window.transform as RectTransform).sizeDelta = Vector3.zero;  | 
|         }  | 
|   | 
|   | 
|   | 
|         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);  | 
|         }  | 
|   | 
|         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 考虑安卓环境  | 
|         IEnumerator 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);  | 
|             yield return 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 void InitTable(Action OnComplete = null)  | 
|         {  | 
|             StartCoroutine(ReadText("InitialFunction", (isOK, value) =>  | 
|             {  | 
|                 if (isOK)  | 
|                 {  | 
|                     InitialFunctionConfig.Init(value);  | 
|                     OnComplete();  | 
|                 }  | 
|                 else  | 
|                 {  | 
|                     Debug.LogError("InitTable InitialFunctionConfig error");  | 
|                 }  | 
|             }));  | 
|             if (isPCTestDownLoad || Application.isMobilePlatform)  | 
|             {  | 
|                 //读取的一定是StreamingAssetPath路径  | 
|                 StartCoroutine(ReadText("logicbytes", (isOK, value) =>  | 
|                 {  | 
|                     if (isOK)  | 
|                         InitLocalLogicbytes(value);  | 
|                     else  | 
|                         Debug.LogError("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);  | 
|                         localAssetVersions[assetVersion.relativePath] = assetVersion;  | 
|                     }  | 
|                     catch (System.Exception ex)  | 
|                     {  | 
|                         Debug.LogError(ex);  | 
|                     }  | 
|                 }  | 
|             }  | 
|         }  | 
|   | 
|     }  | 
| } |