2025-11-18 09:18:48 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.IO;
|
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using UnityEngine.Networking;
|
|
|
|
|
|
namespace Kill.Base
|
|
|
|
|
|
{
|
|
|
|
|
|
public class NetworkCtrl : MonoBehaviour
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
public static NetworkCtrl Instance;
|
|
|
|
|
|
|
|
|
|
|
|
public string localPath;
|
|
|
|
|
|
public string streamingPath;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Awake()
|
|
|
|
|
|
{
|
|
|
|
|
|
Instance = this;
|
|
|
|
|
|
localPath = Application.persistentDataPath;
|
|
|
|
|
|
streamingPath = Application.streamingAssetsPath;
|
|
|
|
|
|
}
|
|
|
|
|
|
async Task Start()
|
|
|
|
|
|
{
|
|
|
|
|
|
nowResourceUrl = resourceUrls[nowResourceIndex];
|
|
|
|
|
|
#if UNITY_EDITOR_WIN
|
|
|
|
|
|
platform = "Windows";
|
|
|
|
|
|
#elif UNITY_EDITOR_OSX
|
|
|
|
|
|
platform = "Mac";
|
|
|
|
|
|
#elif UNITY_ANDROID
|
|
|
|
|
|
platform = "Android";
|
|
|
|
|
|
#elif UNITY_IOS
|
|
|
|
|
|
platform = "iOS";
|
|
|
|
|
|
#endif
|
|
|
|
|
|
await Init();
|
|
|
|
|
|
}
|
|
|
|
|
|
public async Task Init()
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Log("初始化网络控制");
|
2026-03-30 16:25:00 +08:00
|
|
|
|
AndroidStatusBar.statusBarState = AndroidStatusBar.States.TranslucentOverContent;
|
|
|
|
|
|
// 检查并清理过期资源
|
|
|
|
|
|
CheckAndCleanOutdatedResources();
|
|
|
|
|
|
if (LoadRes.Instance.resPosition == LoadRes.ResPosition.资源包)
|
|
|
|
|
|
{
|
|
|
|
|
|
await GetNowBundleList();
|
|
|
|
|
|
if (nowResVersion < new Version(resourceVersion))
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Log("111");
|
|
|
|
|
|
await GetBundleList();
|
|
|
|
|
|
await UpdateResources();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// await FireBaseCtrl.Instance.Init();
|
2025-11-18 09:18:48 +08:00
|
|
|
|
await LoadRes.Instance.Init();
|
2026-03-30 16:25:00 +08:00
|
|
|
|
UI.UIManager.Instance.Init();
|
|
|
|
|
|
|
2025-11-18 09:18:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
#region 资源更新
|
|
|
|
|
|
public string[] resourceUrls;
|
|
|
|
|
|
public int nowResourceIndex;
|
|
|
|
|
|
string nowResourceUrl;
|
|
|
|
|
|
public string resourceVersion;
|
|
|
|
|
|
string platform;
|
2026-03-30 16:25:00 +08:00
|
|
|
|
Version nowResVersion = new Version("0.0.0");
|
2025-11-18 09:18:48 +08:00
|
|
|
|
public AssetBundleInfoList nowBundleList;
|
|
|
|
|
|
public AssetBundleInfoList newBundleList;
|
2026-03-30 16:25:00 +08:00
|
|
|
|
public async Task GetNowBundleList()
|
2025-11-18 09:18:48 +08:00
|
|
|
|
{
|
2026-03-30 16:25:00 +08:00
|
|
|
|
string localListPath = localPath + "/list.json";
|
|
|
|
|
|
string streamingListPath = streamingPath + "/list.json";
|
|
|
|
|
|
|
|
|
|
|
|
// 首先尝试从持久化路径读取
|
|
|
|
|
|
if (File.Exists(localListPath))
|
2025-11-18 09:18:48 +08:00
|
|
|
|
{
|
2026-03-30 16:25:00 +08:00
|
|
|
|
nowBundleList = JsonUtility.FromJson<AssetBundleInfoList>(File.ReadAllText(localListPath));
|
|
|
|
|
|
Debug.Log("===获取本地资源列表成功");
|
|
|
|
|
|
}
|
|
|
|
|
|
// 如果本地没有,则从 StreamingAssets 读取
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
string listJson = await ReadTextFileFromStreamingAssets(streamingListPath);
|
|
|
|
|
|
if (!string.IsNullOrEmpty(listJson))
|
|
|
|
|
|
{
|
|
|
|
|
|
nowBundleList = JsonUtility.FromJson<AssetBundleInfoList>(listJson);
|
|
|
|
|
|
Debug.Log("===获取更包资源列表成功");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Log("===没有获取资源列表");
|
|
|
|
|
|
nowBundleList = null;
|
|
|
|
|
|
}
|
2025-11-18 09:18:48 +08:00
|
|
|
|
}
|
2026-03-30 16:25:00 +08:00
|
|
|
|
if (nowBundleList != null)
|
2025-11-18 09:18:48 +08:00
|
|
|
|
{
|
2026-03-30 16:25:00 +08:00
|
|
|
|
nowResVersion = new Version(nowBundleList.version);
|
2025-11-18 09:18:48 +08:00
|
|
|
|
}
|
2026-03-30 16:25:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 检查并清理过期的本地资源
|
|
|
|
|
|
/// 通过比较版本号判断是否需要清理
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public async void CheckAndCleanOutdatedResources()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 获取StreamingAssets中的资源列表
|
|
|
|
|
|
string streamingListPath = Path.Combine(streamingPath, "list.json");
|
|
|
|
|
|
string streamingListJson = await ReadTextFileFromStreamingAssets(streamingListPath);
|
|
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(streamingListJson))
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AssetBundleInfoList streamingBundleList = JsonUtility.FromJson<AssetBundleInfoList>(streamingListJson);
|
|
|
|
|
|
|
|
|
|
|
|
// 获取本地资源列表
|
|
|
|
|
|
string localListPath = Path.Combine(localPath, "list.json");
|
|
|
|
|
|
if (!File.Exists(localListPath))
|
|
|
|
|
|
{
|
|
|
|
|
|
// 本地没有资源列表,不需要清理
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string localListJson = File.ReadAllText(localListPath);
|
|
|
|
|
|
AssetBundleInfoList localBundleList = JsonUtility.FromJson<AssetBundleInfoList>(localListJson);
|
|
|
|
|
|
|
|
|
|
|
|
// 比较版本号
|
|
|
|
|
|
if (new Version(streamingBundleList.version) >= new Version(localBundleList.version))
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Log($"检测到资源版本更新: {localBundleList.version} -> {streamingBundleList.version},正在清理本地过期资源...");
|
|
|
|
|
|
|
|
|
|
|
|
// 版本不一致,清理本地所有.ab文件
|
|
|
|
|
|
CleanLocalAssetBundleFiles();
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Log($"本地资源版本({localBundleList.version})更新,无需清理");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
2025-11-18 09:18:48 +08:00
|
|
|
|
{
|
2026-03-30 16:25:00 +08:00
|
|
|
|
Debug.LogError($"检查资源版本时出错: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 清理本地的所有AssetBundle文件
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void CleanLocalAssetBundleFiles()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 删除本地所有的.ab文件
|
|
|
|
|
|
string[] localAbFiles = Directory.GetFiles(localPath, "*.ab", SearchOption.AllDirectories);
|
|
|
|
|
|
foreach (string abFile in localAbFiles)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
File.Delete(abFile);
|
|
|
|
|
|
Debug.Log($"已删除过期资源文件: {abFile}");
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"删除文件失败 {abFile}: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
File.Delete(localPath + "/list.json");
|
|
|
|
|
|
Debug.Log("本地过期资源清理完成");
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"清理本地资源时出错: {ex.Message}");
|
2025-11-18 09:18:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
public async Task GetBundleList()
|
|
|
|
|
|
{
|
|
|
|
|
|
string url = nowResourceUrl + $"{resourceVersion}/{platform}/list.json";
|
|
|
|
|
|
using (UnityWebRequest webRequest = UnityWebRequest.Get(url))
|
|
|
|
|
|
{
|
|
|
|
|
|
var operation = webRequest.SendWebRequest();
|
|
|
|
|
|
while (!operation.isDone)
|
|
|
|
|
|
{
|
|
|
|
|
|
await Task.Yield();
|
|
|
|
|
|
}
|
|
|
|
|
|
if (webRequest.result == UnityWebRequest.Result.Success)
|
|
|
|
|
|
{
|
|
|
|
|
|
AssetBundleInfoList list = JsonUtility.FromJson<AssetBundleInfoList>(webRequest.downloadHandler.text);
|
|
|
|
|
|
newBundleList = list;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError(url + "获取资源列表失败" + webRequest.error);
|
2026-03-30 16:25:00 +08:00
|
|
|
|
// ErrorTip.Instance.Init("获取资源列表失败", url, async (msg) =>
|
|
|
|
|
|
// {
|
|
|
|
|
|
// await GetBundleList();
|
|
|
|
|
|
// });
|
2025-11-18 09:18:48 +08:00
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-03-30 16:25:00 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 从StreamingAssets目录读取文本文件(兼容各平台)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="filePath">文件路径</param>
|
|
|
|
|
|
/// <returns>文件内容</returns>
|
|
|
|
|
|
private async Task<string> ReadTextFileFromStreamingAssets(string filePath)
|
|
|
|
|
|
{
|
|
|
|
|
|
string result = null;
|
2025-11-18 09:18:48 +08:00
|
|
|
|
|
2026-03-30 16:25:00 +08:00
|
|
|
|
#if UNITY_ANDROID && !UNITY_EDITOR
|
|
|
|
|
|
// Android平台特殊处理
|
|
|
|
|
|
UnityWebRequest www = UnityWebRequest.Get(filePath);
|
|
|
|
|
|
var operation = www.SendWebRequest();
|
|
|
|
|
|
|
|
|
|
|
|
// 等待请求完成
|
|
|
|
|
|
while (!operation.isDone)
|
|
|
|
|
|
{
|
|
|
|
|
|
await Task.Yield();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (www.result == UnityWebRequest.Result.Success)
|
|
|
|
|
|
{
|
|
|
|
|
|
result = www.downloadHandler.text;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"读取StreamingAssets文件失败: {www.error}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
www.Dispose();
|
|
|
|
|
|
#else
|
|
|
|
|
|
// 其他平台可以直接访问文件系统
|
|
|
|
|
|
if (File.Exists(filePath))
|
|
|
|
|
|
{
|
|
|
|
|
|
result = File.ReadAllText(filePath);
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
2025-11-18 09:18:48 +08:00
|
|
|
|
public async Task UpdateResources()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 获取更新列表
|
|
|
|
|
|
List<AssetBundleInfo> updateList = GetUpdateList();
|
|
|
|
|
|
|
|
|
|
|
|
if (updateList.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 开始下载更新
|
|
|
|
|
|
bool success = await DownloadUpdateFiles(updateList, (downloaded, total) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
float progress = (float)downloaded / total;
|
|
|
|
|
|
Debug.Log($"更新进度: {progress:P}");
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (success)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Log("资源更新完成");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("资源更新失败");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Log("资源已是最新版本");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 对比当前资源列表和新资源列表,找出需要更新的文件
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns>需要更新的资源信息列表</returns>
|
|
|
|
|
|
public List<AssetBundleInfo> GetUpdateList()
|
|
|
|
|
|
{
|
|
|
|
|
|
List<AssetBundleInfo> updateList = new List<AssetBundleInfo>();
|
|
|
|
|
|
|
|
|
|
|
|
// 如果没有当前列表,则全部都需要下载
|
|
|
|
|
|
if (nowBundleList == null || nowBundleList.assetbundles == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return newBundleList.assetbundles ?? new List<AssetBundleInfo>();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建当前资源字典以便快速查找
|
|
|
|
|
|
Dictionary<string, AssetBundleInfo> nowBundleDict = new Dictionary<string, AssetBundleInfo>();
|
|
|
|
|
|
foreach (var bundle in nowBundleList.assetbundles)
|
|
|
|
|
|
{
|
|
|
|
|
|
nowBundleDict[bundle.name] = bundle;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 对比新资源列表
|
|
|
|
|
|
foreach (var newBundle in newBundleList.assetbundles)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 检查文件是否存在或MD5是否不匹配
|
|
|
|
|
|
if (!nowBundleDict.ContainsKey(newBundle.name) ||
|
|
|
|
|
|
nowBundleDict[newBundle.name].md5 != newBundle.md5)
|
|
|
|
|
|
{
|
|
|
|
|
|
updateList.Add(newBundle);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return updateList;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 计算需要更新的总大小
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="updateList">需要更新的资源列表</param>
|
|
|
|
|
|
/// <returns>总大小(字节)</returns>
|
|
|
|
|
|
public long CalculateUpdateSize(List<AssetBundleInfo> updateList)
|
|
|
|
|
|
{
|
|
|
|
|
|
long totalSize = 0;
|
|
|
|
|
|
foreach (var bundle in updateList)
|
|
|
|
|
|
{
|
|
|
|
|
|
totalSize += bundle.size;
|
|
|
|
|
|
}
|
|
|
|
|
|
return totalSize;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 下载更新文件并实时返回进度
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="updateList">需要更新的资源列表</param>
|
|
|
|
|
|
/// <param name="progressCallback">进度回调(已下载字节数, 总字节数)</param>
|
|
|
|
|
|
/// <returns>是否下载成功</returns>
|
|
|
|
|
|
public async Task<bool> DownloadUpdateFiles(List<AssetBundleInfo> updateList, Action<long, long> progressCallback)
|
|
|
|
|
|
{
|
|
|
|
|
|
long totalSize = CalculateUpdateSize(updateList);
|
|
|
|
|
|
long downloadedSize = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化 nowBundleList(如果为空)
|
|
|
|
|
|
if (nowBundleList == null || nowBundleList.assetbundles == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
nowBundleList = new AssetBundleInfoList(new List<AssetBundleInfo>());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建当前资源字典以便快速查找和更新
|
|
|
|
|
|
Dictionary<string, AssetBundleInfo> nowBundleDict = new Dictionary<string, AssetBundleInfo>();
|
|
|
|
|
|
foreach (var bundle in nowBundleList.assetbundles)
|
|
|
|
|
|
{
|
|
|
|
|
|
nowBundleDict[bundle.name] = bundle;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var bundle in updateList)
|
|
|
|
|
|
{
|
|
|
|
|
|
string url = nowResourceUrl + $"{resourceVersion}/{platform}/{bundle.name}";
|
|
|
|
|
|
string savePath = Path.Combine(localPath, bundle.name);
|
|
|
|
|
|
|
|
|
|
|
|
// 确保目录存在
|
|
|
|
|
|
string directory = Path.GetDirectoryName(savePath);
|
|
|
|
|
|
if (!Directory.Exists(directory))
|
|
|
|
|
|
{
|
|
|
|
|
|
Directory.CreateDirectory(directory);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool downloadSuccess = await DownloadSingleFile(url, savePath, bundle.md5);
|
|
|
|
|
|
if (!downloadSuccess)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"下载文件失败: {bundle.name}");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 下载成功后,更新 nowBundleList
|
|
|
|
|
|
nowBundleDict[bundle.name] = bundle;
|
|
|
|
|
|
downloadedSize += bundle.size;
|
|
|
|
|
|
progressCallback?.Invoke(downloadedSize, totalSize);
|
|
|
|
|
|
|
|
|
|
|
|
// 简短延迟避免请求过于频繁
|
|
|
|
|
|
await Task.Yield();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新完整的 nowBundleList
|
|
|
|
|
|
nowBundleList.assetbundles = new List<AssetBundleInfo>(nowBundleDict.Values);
|
2026-03-30 16:25:00 +08:00
|
|
|
|
nowBundleList.version = resourceVersion;
|
2025-11-18 09:18:48 +08:00
|
|
|
|
// 下载完成后保存新的list.json
|
|
|
|
|
|
SaveNewBundleList();
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 下载单个文件并校验MD5
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="url">文件URL</param>
|
|
|
|
|
|
/// <param name="savePath">保存路径</param>
|
|
|
|
|
|
/// <param name="expectedMd5">期望的MD5值</param>
|
|
|
|
|
|
/// <returns>是否下载并校验成功</returns>
|
|
|
|
|
|
private async Task<bool> DownloadSingleFile(string url, string savePath, string expectedMd5)
|
|
|
|
|
|
{
|
|
|
|
|
|
int maxRetries = 2;
|
|
|
|
|
|
for (int i = 0; i <= maxRetries; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
using (UnityWebRequest webRequest = UnityWebRequest.Get(url))
|
|
|
|
|
|
{
|
|
|
|
|
|
var operation = webRequest.SendWebRequest();
|
|
|
|
|
|
while (!operation.isDone)
|
|
|
|
|
|
{
|
|
|
|
|
|
await Task.Yield();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (webRequest.result == UnityWebRequest.Result.Success)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 保存文件
|
|
|
|
|
|
File.WriteAllBytes(savePath, webRequest.downloadHandler.data);
|
|
|
|
|
|
|
|
|
|
|
|
// 校验MD5
|
|
|
|
|
|
string actualMd5 = CalculateMD5(savePath);
|
|
|
|
|
|
if (actualMd5.ToLower() == expectedMd5.ToLower())
|
|
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"MD5校验失败 {url}: 期望 {expectedMd5}, 实际 {actualMd5}");
|
|
|
|
|
|
// MD5校验失败时删除文件
|
|
|
|
|
|
if (File.Exists(savePath))
|
|
|
|
|
|
{
|
|
|
|
|
|
File.Delete(savePath);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"下载失败 {url}: {webRequest.error} (尝试 {i + 1}/{maxRetries + 1})");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果还没达到最大重试次数,等待一段时间后重试
|
|
|
|
|
|
if (i < maxRetries)
|
|
|
|
|
|
{
|
|
|
|
|
|
await Task.Delay(1000 * (i + 1)); // 递增延迟时间
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 所有重试都失败后显示错误提示
|
|
|
|
|
|
ErrorTip.Instance.Init("下载资源包失败", url, async (msg) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
// 错误处理回调 - 重新尝试下载更新资源流程
|
|
|
|
|
|
Debug.Log("用户选择重试下载资源包");
|
|
|
|
|
|
await UpdateResources();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 计算文件的MD5值
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="filePath">文件路径</param>
|
|
|
|
|
|
/// <returns>MD5值</returns>
|
|
|
|
|
|
private string CalculateMD5(string filePath)
|
|
|
|
|
|
{
|
|
|
|
|
|
using (var md5 = System.Security.Cryptography.MD5.Create())
|
|
|
|
|
|
{
|
|
|
|
|
|
using (var stream = File.OpenRead(filePath))
|
|
|
|
|
|
{
|
|
|
|
|
|
byte[] hash = md5.ComputeHash(stream);
|
|
|
|
|
|
return BitConverter.ToString(hash).Replace("-", "").ToLower();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 保存新的资源列表到本地
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void SaveNewBundleList()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (newBundleList != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
string json = JsonUtility.ToJson(newBundleList, true);
|
|
|
|
|
|
string savePath = Path.Combine(localPath, "list.json");
|
|
|
|
|
|
File.WriteAllText(savePath, json);
|
|
|
|
|
|
Debug.Log("新的资源列表已保存到本地");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-03-30 16:25:00 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
#region 通用网络请求
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
2025-11-18 09:18:48 +08:00
|
|
|
|
}
|
2026-03-30 16:25:00 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-11-18 09:18:48 +08:00
|
|
|
|
}
|