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 { //不下载时本地安卓测试路径 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 int downLoadCount = 0; 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 assetVersions = new Dictionary(); //本地LogicBytes文件和 assetVersions 比较是否需要下载 public Dictionary localAssetVersions = new Dictionary(); public static string versionUrlResult { get; private set; } /// /// 语言的ID,用于区分下载资源 /// /// 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(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(); 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(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(path); // } // else // { var spriteAtlas = UnityEditor.AssetDatabase.LoadAssetAtPath("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(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; } static Dictionary languageShowDict = new Dictionary();//射中显示的多语言版本 Dictionary languageDict = new Dictionary();// unity语言配置对应的约定字符 string defaultLanguage = string.Empty; public void InitDefaultLanguage() { if (languageShowDict == null || languageShowDict.Count == 0) { var config = InitialFunctionConfig.Get("Language"); Debug.LogFormat("系统语言:{0} {1}", Application.systemLanguage, config.Numerical1); if (string.IsNullOrEmpty(config.Numerical1)) return; languageShowDict = JsonMapper.ToObject>(config.Numerical1); languageDict = JsonMapper.ToObject>(config.Numerical5); defaultLanguage = config.Numerical2; if (!languageShowDict.ContainsKey(defaultLanguage)) defaultLanguage = string.Empty; } var id = LocalSave.GetString("LANGUAGE_ID1"); if (!string.IsNullOrEmpty(id)) return; string languageMark = ((int)Application.systemLanguage).ToString(); if (languageDict.ContainsKey(languageMark)) { id = languageDict[languageMark]; } Id = languageShowDict.ContainsKey(id) ? id : defaultLanguage; Debug.LogFormat("系统语言:{0} 设置为{1}", Application.systemLanguage, Id); } //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 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 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, } }