提交
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 2286bdb9423d4da48ba3b1bd8765173f
|
guid: 410e26deedfc5864bb5bd6b9cad1f450
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2286bdb9423d4da48ba3b1bd8765173f
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -16,42 +16,51 @@ using UnityEditor;
|
|||||||
#if USE_ADDRESSABLES
|
#if USE_ADDRESSABLES
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace SGModule.ConfigLoader {
|
namespace SGModule.ConfigLoader
|
||||||
public class FileNetworkManager : SingletonMonoBehaviour<FileNetworkManager> {
|
{
|
||||||
|
public class FileNetworkManager : SingletonMonoBehaviour<FileNetworkManager>
|
||||||
|
{
|
||||||
public const string FolderName = "Configs";
|
public const string FolderName = "Configs";
|
||||||
private const string FolderLabel = "config";
|
private const string FolderLabel = "config";
|
||||||
private string _configFolderPath;
|
private string _configFolderPath;
|
||||||
|
|
||||||
protected override void Awake() {
|
protected override void Awake()
|
||||||
|
{
|
||||||
base.Awake();
|
base.Awake();
|
||||||
|
|
||||||
_configFolderPath = Path.Combine(Application.persistentDataPath, FolderName);
|
_configFolderPath = Path.Combine(Application.persistentDataPath, FolderName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetConfigFOlderPath() {
|
public string GetConfigFOlderPath()
|
||||||
|
{
|
||||||
return _configFolderPath;
|
return _configFolderPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 示例解析文件列表方法(你可以根据实际需求实现)
|
// 示例解析文件列表方法(你可以根据实际需求实现)
|
||||||
private List<string> ParseFileList(string data) {
|
private List<string> ParseFileList(string data)
|
||||||
|
{
|
||||||
// 假设 data 是文件列表的文本,解析文件名
|
// 假设 data 是文件列表的文本,解析文件名
|
||||||
// 根据实际情况解析,例如通过换行符分割
|
// 根据实际情况解析,例如通过换行符分割
|
||||||
return data.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
return data.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CopyStreamingAssetsToPersistentDataPath(Action<bool> onComplete = null) {
|
public void CopyStreamingAssetsToPersistentDataPath(Action<bool> onComplete = null)
|
||||||
|
{
|
||||||
// 如果目标文件夹不存在,创建它
|
// 如果目标文件夹不存在,创建它
|
||||||
if (!Directory.Exists(_configFolderPath)) {
|
if (!Directory.Exists(_configFolderPath))
|
||||||
|
{
|
||||||
Directory.CreateDirectory(_configFolderPath);
|
Directory.CreateDirectory(_configFolderPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
StartCoroutine(CopyFile(onComplete));
|
StartCoroutine(CopyFile(onComplete));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleInitializationError() {
|
private void HandleInitializationError()
|
||||||
|
{
|
||||||
// 检查文件是否存在
|
// 检查文件是否存在
|
||||||
var path = $"{Application.dataPath}/Library/com.unity.addressables/aa/Android/settings.json";
|
var path = $"{Application.dataPath}/Library/com.unity.addressables/aa/Android/settings.json";
|
||||||
if (!File.Exists(path)) {
|
if (!File.Exists(path))
|
||||||
|
{
|
||||||
Log.ConfigLoader.Warning(
|
Log.ConfigLoader.Warning(
|
||||||
$"Settings file not found at: {path}. Rebuilding Addressables may be required.");
|
$"Settings file not found at: {path}. Rebuilding Addressables may be required.");
|
||||||
}
|
}
|
||||||
@@ -61,67 +70,75 @@ namespace SGModule.ConfigLoader {
|
|||||||
// 比如:显示弹窗或退出程序
|
// 比如:显示弹窗或退出程序
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerator CopyFile(Action<bool> onComplete = null) {
|
private IEnumerator CopyFile(Action<bool> onComplete = null)
|
||||||
|
{
|
||||||
#if USE_ADDRESSABLES
|
#if USE_ADDRESSABLES
|
||||||
var handle = Addressables.LoadResourceLocationsAsync(FolderLabel);
|
var handle = Addressables.LoadResourceLocationsAsync(FolderLabel);
|
||||||
|
|
||||||
yield return handle;
|
yield return handle;
|
||||||
|
|
||||||
if (handle.Status == AsyncOperationStatus.Succeeded) {
|
// if (handle.Status == AsyncOperationStatus.Succeeded) {
|
||||||
// 查找以 ".json" 结尾的文件
|
// 查找以 ".json" 结尾的文件
|
||||||
var jsonLocation = handle.Result.FirstOrDefault(loc => loc.PrimaryKey.EndsWith(".json"));
|
// var jsonLocation = handle.Result.FirstOrDefault(loc => loc.PrimaryKey.EndsWith(".json"));
|
||||||
|
|
||||||
if (jsonLocation != null) {
|
// if (jsonLocation != null) {
|
||||||
var jsonFileName = Path.GetFileName(jsonLocation.PrimaryKey);
|
// var jsonFileName = Path.GetFileName(jsonLocation.PrimaryKey);
|
||||||
// 加载 JSON 文件
|
// 加载 JSON 文件
|
||||||
var textAssetAsync = Addressables.LoadAssetAsync<TextAsset>(jsonLocation);
|
// var textAssetAsync = Addressables.LoadAssetAsync<TextAsset>(jsonLocation);
|
||||||
|
TextAsset[] files = Resources.LoadAll<TextAsset>("Configs");
|
||||||
|
// yield return textAssetAsync;
|
||||||
|
|
||||||
yield return textAssetAsync;
|
// if (textAssetAsync.Status == AsyncOperationStatus.Succeeded)
|
||||||
|
// {
|
||||||
if (textAssetAsync.Status == AsyncOperationStatus.Succeeded) {
|
TextAsset jsonFile = files[0];
|
||||||
var jsonFile = textAssetAsync.Result;
|
string jsonFileName = jsonFile.name;
|
||||||
Log.ConfigLoader.Info($"Loaded JSON Name:{jsonFileName} content: " + jsonFile.text);
|
Log.ConfigLoader.Info($"Loaded JSON Name:{jsonFileName} content: " + jsonFile.text);
|
||||||
|
|
||||||
|
|
||||||
var destFilePath = Path.Combine(_configFolderPath, jsonFileName);
|
var destFilePath = Path.Combine(_configFolderPath, jsonFileName);
|
||||||
File.WriteAllBytes(destFilePath, jsonFile.bytes);
|
File.WriteAllBytes(destFilePath, jsonFile.bytes);
|
||||||
onComplete?.Invoke(true);
|
onComplete?.Invoke(true);
|
||||||
}
|
// }
|
||||||
else {
|
// else {
|
||||||
Log.ConfigLoader.Error("Failed to load JSON file");
|
// Log.ConfigLoader.Error("Failed to load JSON file");
|
||||||
|
|
||||||
onComplete?.Invoke(false);
|
// onComplete?.Invoke(false);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
else {
|
// else {
|
||||||
Log.ConfigLoader.Error("No JSON file found in folder");
|
// Log.ConfigLoader.Error("No JSON file found in folder");
|
||||||
|
|
||||||
onComplete?.Invoke(false);
|
// onComplete?.Invoke(false);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
else {
|
// else
|
||||||
Log.ConfigLoader.Error("Failed to load folder resources");
|
// {
|
||||||
|
// Log.ConfigLoader.Error("Failed to load folder resources");
|
||||||
|
|
||||||
onComplete?.Invoke(false);
|
// onComplete?.Invoke(false);
|
||||||
}
|
// }
|
||||||
#else
|
#else
|
||||||
Log.Error( "没有 Addressables 插件,请检查 ");
|
Log.Error( "没有 Addressables 插件,请检查 ");
|
||||||
yield break;
|
yield break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerator CopyFile(string sourceFile, string destFile, Action<bool> onComplete = null) {
|
private IEnumerator CopyFile(string sourceFile, string destFile, Action<bool> onComplete = null)
|
||||||
|
{
|
||||||
var filePath = "file://" + sourceFile;
|
var filePath = "file://" + sourceFile;
|
||||||
|
|
||||||
using (var www = UnityWebRequest.Get(filePath)) {
|
using (var www = UnityWebRequest.Get(filePath))
|
||||||
|
{
|
||||||
yield return www.SendWebRequest();
|
yield return www.SendWebRequest();
|
||||||
|
|
||||||
if (www.result == UnityWebRequest.Result.Success) {
|
if (www.result == UnityWebRequest.Result.Success)
|
||||||
|
{
|
||||||
File.WriteAllBytes(destFile, www.downloadHandler.data);
|
File.WriteAllBytes(destFile, www.downloadHandler.data);
|
||||||
Log.ConfigLoader.Info($"File copied to {destFile}");
|
Log.ConfigLoader.Info($"File copied to {destFile}");
|
||||||
onComplete?.Invoke(true);
|
onComplete?.Invoke(true);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
Log.ConfigLoader.Error("Failed to copy file: " + www.error);
|
Log.ConfigLoader.Error("Failed to copy file: " + www.error);
|
||||||
|
|
||||||
onComplete?.Invoke(false);
|
onComplete?.Invoke(false);
|
||||||
@@ -134,7 +151,8 @@ namespace SGModule.ConfigLoader {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path"></param>
|
/// <param name="path"></param>
|
||||||
/// <param name="callback"></param>
|
/// <param name="callback"></param>
|
||||||
public void ReadData(string path, Action<string> callback) {
|
public void ReadData(string path, Action<string> callback)
|
||||||
|
{
|
||||||
StartCoroutine(ReadDataEnumerator(path, callback));
|
StartCoroutine(ReadDataEnumerator(path, callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,14 +162,17 @@ namespace SGModule.ConfigLoader {
|
|||||||
/// <param name="path"></param>
|
/// <param name="path"></param>
|
||||||
/// <param name="callback"></param>
|
/// <param name="callback"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private IEnumerator ReadDataEnumerator(string path, Action<string> callback) {
|
private IEnumerator ReadDataEnumerator(string path, Action<string> callback)
|
||||||
|
{
|
||||||
string fullPath;
|
string fullPath;
|
||||||
|
|
||||||
// 判断是网络URL还是本地文件路径
|
// 判断是网络URL还是本地文件路径
|
||||||
if (path.StartsWith("http://") || path.StartsWith("https://")) {
|
if (path.StartsWith("http://") || path.StartsWith("https://"))
|
||||||
|
{
|
||||||
fullPath = path; // 网络URL
|
fullPath = path; // 网络URL
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
if (path.StartsWith("http://") && PlayerSettings.insecureHttpOption == InsecureHttpOption.NotAllowed) {
|
if (path.StartsWith("http://") && PlayerSettings.insecureHttpOption == InsecureHttpOption.NotAllowed)
|
||||||
|
{
|
||||||
Log.ConfigLoader.Error("发起了 HTTP 链接,但设置了不允许非Https连接,请检查设置!!!");
|
Log.ConfigLoader.Error("发起了 HTTP 链接,但设置了不允许非Https连接,请检查设置!!!");
|
||||||
|
|
||||||
callback?.Invoke(null);
|
callback?.Invoke(null);
|
||||||
@@ -159,22 +180,26 @@ namespace SGModule.ConfigLoader {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
// 本地文件路径
|
// 本地文件路径
|
||||||
fullPath = "file://" + path;
|
fullPath = "file://" + path;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用UnityWebRequest读取数据
|
// 使用UnityWebRequest读取数据
|
||||||
using (var webRequest = UnityWebRequest.Get(fullPath)) {
|
using (var webRequest = UnityWebRequest.Get(fullPath))
|
||||||
|
{
|
||||||
yield return webRequest.SendWebRequest();
|
yield return webRequest.SendWebRequest();
|
||||||
|
|
||||||
if (webRequest.result == UnityWebRequest.Result.ConnectionError ||
|
if (webRequest.result == UnityWebRequest.Result.ConnectionError ||
|
||||||
webRequest.result == UnityWebRequest.Result.ProtocolError) {
|
webRequest.result == UnityWebRequest.Result.ProtocolError)
|
||||||
|
{
|
||||||
Log.ConfigLoader.Error($"Error while reading file: {webRequest.error} path: {fullPath}");
|
Log.ConfigLoader.Error($"Error while reading file: {webRequest.error} path: {fullPath}");
|
||||||
|
|
||||||
callback?.Invoke(null); // 返回null表示出错
|
callback?.Invoke(null); // 返回null表示出错
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
var data = webRequest.downloadHandler.text;
|
var data = webRequest.downloadHandler.text;
|
||||||
callback?.Invoke(data); // 通过回调传出数据
|
callback?.Invoke(data); // 通过回调传出数据
|
||||||
}
|
}
|
||||||
@@ -187,18 +212,21 @@ namespace SGModule.ConfigLoader {
|
|||||||
/// <param name="folderName">文件夹名称</param>
|
/// <param name="folderName">文件夹名称</param>
|
||||||
/// <param name="fileName">文件名称</param>
|
/// <param name="fileName">文件名称</param>
|
||||||
/// <param name="content">要写入的内容</param>
|
/// <param name="content">要写入的内容</param>
|
||||||
public void WriteToPersistentData(string folderName, string fileName, string content) {
|
public void WriteToPersistentData(string folderName, string fileName, string content)
|
||||||
|
{
|
||||||
// 获取持久化数据路径
|
// 获取持久化数据路径
|
||||||
var folderPath = Path.Combine(Application.persistentDataPath, folderName);
|
var folderPath = Path.Combine(Application.persistentDataPath, folderName);
|
||||||
|
|
||||||
// 如果文件夹不存在,则创建它
|
// 如果文件夹不存在,则创建它
|
||||||
if (!Directory.Exists(folderPath)) {
|
if (!Directory.Exists(folderPath))
|
||||||
|
{
|
||||||
Directory.CreateDirectory(folderPath);
|
Directory.CreateDirectory(folderPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除原有文件
|
// 删除原有文件
|
||||||
var existingFiles = Directory.GetFiles(folderPath);
|
var existingFiles = Directory.GetFiles(folderPath);
|
||||||
foreach (var file in existingFiles) {
|
foreach (var file in existingFiles)
|
||||||
|
{
|
||||||
File.Delete(file);
|
File.Delete(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,11 +245,12 @@ namespace SGModule.ConfigLoader {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="subdirectory"></param>
|
/// <param name="subdirectory"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public string[] GetFileNamesFromPersistentDataPath(string subdirectory) {
|
public string[] GetFileNamesFromPersistentDataPath(string subdirectory)
|
||||||
|
{
|
||||||
var directoryPath = Path.Combine(Application.persistentDataPath, subdirectory);
|
var directoryPath = Path.Combine(Application.persistentDataPath, subdirectory);
|
||||||
|
|
||||||
if (Directory.Exists(directoryPath))
|
if (Directory.Exists(directoryPath))
|
||||||
// 获取目录中的所有文件名
|
// 获取目录中的所有文件名
|
||||||
{
|
{
|
||||||
return Directory.GetFiles(directoryPath)
|
return Directory.GetFiles(directoryPath)
|
||||||
.Select(Path.GetFileName) // 只提取文件名
|
.Select(Path.GetFileName) // 只提取文件名
|
||||||
|
|||||||
@@ -7,20 +7,24 @@ using SGModule.Common.Helper;
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Networking;
|
using UnityEngine.Networking;
|
||||||
|
|
||||||
namespace SGModule.Net {
|
namespace SGModule.Net
|
||||||
public enum ConnectionStatus {
|
{
|
||||||
|
public enum ConnectionStatus
|
||||||
|
{
|
||||||
Uninitialized, // 未初始化
|
Uninitialized, // 未初始化
|
||||||
Connected, // 已连接
|
Connected, // 已连接
|
||||||
Disconnected // 未连接
|
Disconnected // 未连接
|
||||||
}
|
}
|
||||||
|
|
||||||
// 网络检测类
|
// 网络检测类
|
||||||
public class NetChecker : SingletonMonoBehaviour<NetChecker> {
|
public class NetChecker : SingletonMonoBehaviour<NetChecker>
|
||||||
|
{
|
||||||
private const float WebRequestInterval = 5f;
|
private const float WebRequestInterval = 5f;
|
||||||
private const float PingInterval = 2;
|
private const float PingInterval = 2;
|
||||||
|
|
||||||
// 可配置多个检测 URL
|
// 可配置多个检测 URL
|
||||||
[SerializeField] private List<string> checkUrls = new() {
|
[SerializeField]
|
||||||
|
private List<string> checkUrls = new() {
|
||||||
"https://www.baidu.com", // 国内 URL
|
"https://www.baidu.com", // 国内 URL
|
||||||
"https://www.google.com" // 国外 URL
|
"https://www.google.com" // 国外 URL
|
||||||
};
|
};
|
||||||
@@ -45,16 +49,19 @@ namespace SGModule.Net {
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// null = 未检测;true = 联网;false = 未联网
|
/// null = 未检测;true = 联网;false = 未联网
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private bool? IsConnected {
|
private bool? IsConnected
|
||||||
|
{
|
||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEnable() {
|
private void OnEnable()
|
||||||
|
{
|
||||||
StartCheckingInternet();
|
StartCheckingInternet();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDisable() {
|
private void OnDisable()
|
||||||
|
{
|
||||||
StopCheckingInternet();
|
StopCheckingInternet();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,69 +71,84 @@ namespace SGModule.Net {
|
|||||||
/// <param name="timeout">最多等待的总时间(秒)</param>
|
/// <param name="timeout">最多等待的总时间(秒)</param>
|
||||||
/// <param name="checkInterval">每次重试间隔</param>
|
/// <param name="checkInterval">每次重试间隔</param>
|
||||||
/// <param name="callback">检测结果回调</param>
|
/// <param name="callback">检测结果回调</param>
|
||||||
public IEnumerator WaitUntilNetworkConnected(float timeout, float checkInterval, Action<bool> callback) {
|
public IEnumerator WaitUntilNetworkConnected(float timeout, float checkInterval, Action<bool> callback)
|
||||||
|
{
|
||||||
var elapsed = 0f;
|
var elapsed = 0f;
|
||||||
|
|
||||||
// 阶段 1: 等待初始化完成
|
// 阶段 1: 等待初始化完成
|
||||||
while (!IsConnected.HasValue && elapsed < timeout) {
|
while (!IsConnected.HasValue && elapsed < timeout)
|
||||||
|
{
|
||||||
yield return new WaitForSeconds(checkInterval);
|
yield return new WaitForSeconds(checkInterval);
|
||||||
elapsed += checkInterval;
|
elapsed += checkInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsConnected.HasValue) {
|
if (!IsConnected.HasValue)
|
||||||
|
{
|
||||||
Log.Net.Warning("网络检测初始化超时!");
|
Log.Net.Warning("网络检测初始化超时!");
|
||||||
callback(false);
|
callback(false);
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 阶段 2: 等待网络恢复
|
// 阶段 2: 等待网络恢复
|
||||||
while (IsConnected == false && elapsed < timeout) {
|
while (IsConnected == false && elapsed < timeout)
|
||||||
|
{
|
||||||
Log.Net.Warning($"网络异常,等待中... 已耗时: {elapsed:F1}s");
|
Log.Net.Warning($"网络异常,等待中... 已耗时: {elapsed:F1}s");
|
||||||
yield return new WaitForSeconds(checkInterval);
|
yield return new WaitForSeconds(checkInterval);
|
||||||
elapsed += checkInterval;
|
elapsed += checkInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
var success = IsConnected == true;
|
var success = IsConnected == true;
|
||||||
if (!success) {
|
if (!success)
|
||||||
|
{
|
||||||
Log.Net.Warning("网络连接等待超时!");
|
Log.Net.Warning("网络连接等待超时!");
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(success);
|
callback(success);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConnectionStatus GetConnectionStatus() {
|
public ConnectionStatus GetConnectionStatus()
|
||||||
return IsConnected switch {
|
{
|
||||||
|
return IsConnected switch
|
||||||
|
{
|
||||||
null => ConnectionStatus.Uninitialized,
|
null => ConnectionStatus.Uninitialized,
|
||||||
true => ConnectionStatus.Connected,
|
true => ConnectionStatus.Connected,
|
||||||
false => ConnectionStatus.Disconnected
|
false => ConnectionStatus.Disconnected
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Init() {
|
public void Init()
|
||||||
|
{
|
||||||
StartCheckingInternet();
|
StartCheckingInternet();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartCheckingInternet() {
|
private void StartCheckingInternet()
|
||||||
|
{
|
||||||
_checkInterval = usePingCheck ? PingInterval : WebRequestInterval;
|
_checkInterval = usePingCheck ? PingInterval : WebRequestInterval;
|
||||||
_checkInternetCoroutine ??= StartCoroutine(CheckInternetRoutine());
|
_checkInternetCoroutine ??= StartCoroutine(CheckInternetRoutine());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StopCheckingInternet() {
|
private void StopCheckingInternet()
|
||||||
if (_checkInternetCoroutine != null) {
|
{
|
||||||
|
if (_checkInternetCoroutine != null)
|
||||||
|
{
|
||||||
StopCoroutine(_checkInternetCoroutine);
|
StopCoroutine(_checkInternetCoroutine);
|
||||||
_checkInternetCoroutine = null;
|
_checkInternetCoroutine = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerator CheckInternetRoutine() {
|
private IEnumerator CheckInternetRoutine()
|
||||||
while (true) {
|
{
|
||||||
if (_isChecking) {
|
while (true)
|
||||||
|
{
|
||||||
|
if (_isChecking)
|
||||||
|
{
|
||||||
yield break; // 避免并发冲突
|
yield break; // 避免并发冲突
|
||||||
}
|
}
|
||||||
|
|
||||||
_isChecking = true;
|
_isChecking = true;
|
||||||
|
|
||||||
if (QuickNetDeviceCheck()) {
|
if (QuickNetDeviceCheck())
|
||||||
|
{
|
||||||
// if (usePingCheck) {
|
// if (usePingCheck) {
|
||||||
yield return CheckWithPing();
|
yield return CheckWithPing();
|
||||||
// }
|
// }
|
||||||
@@ -134,11 +156,13 @@ namespace SGModule.Net {
|
|||||||
// yield return CheckWithUnityWebRequest();
|
// yield return CheckWithUnityWebRequest();
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
IsConnected = false;
|
IsConnected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsConnected.HasValue && _lastConnected != IsConnected.Value) {
|
if (IsConnected.HasValue && _lastConnected != IsConnected.Value)
|
||||||
|
{
|
||||||
Log.Net.Info($"网络状态变化: {IsConnected}");
|
Log.Net.Info($"网络状态变化: {IsConnected}");
|
||||||
_lastConnected = IsConnected.Value;
|
_lastConnected = IsConnected.Value;
|
||||||
}
|
}
|
||||||
@@ -151,42 +175,46 @@ namespace SGModule.Net {
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 使用 Ping 检测网络连通性
|
/// 使用 Ping 检测网络连通性
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private IEnumerator CheckWithPing() {
|
private IEnumerator CheckWithPing()
|
||||||
|
{
|
||||||
var pings = _pingAddresses.Select(ip => new Ping(ip)).ToList();
|
var pings = _pingAddresses.Select(ip => new Ping(ip)).ToList();
|
||||||
|
|
||||||
var startTime = Time.realtimeSinceStartup;
|
var startTime = Time.realtimeSinceStartup;
|
||||||
var success = false;
|
var success = false;
|
||||||
|
|
||||||
// 等待所有 Ping 返回结果或超时
|
// // 等待所有 Ping 返回结果或超时
|
||||||
while (Time.realtimeSinceStartup - startTime < _checkInterval) {
|
// while (Time.realtimeSinceStartup - startTime < _checkInterval) {
|
||||||
foreach (var ping in pings) {
|
// foreach (var ping in pings) {
|
||||||
if (ping.isDone && ping.time >= 0) {
|
// if (ping.isDone && ping.time >= 0) {
|
||||||
success = true;
|
// success = true;
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (success) {
|
// if (success) {
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
|
|
||||||
yield return new WaitForSecondsRealtime(0.1f);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// }
|
||||||
|
yield return new WaitForSecondsRealtime(0.1f);
|
||||||
// 如果有任意一个 Ping 成功,网络即为可用
|
// 如果有任意一个 Ping 成功,网络即为可用
|
||||||
IsConnected = success;
|
IsConnected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 使用 UnityWebRequest 检测网络连通性
|
/// 使用 UnityWebRequest 检测网络连通性
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private IEnumerator CheckWithUnityWebRequest() {
|
private IEnumerator CheckWithUnityWebRequest()
|
||||||
if (!string.IsNullOrEmpty(_preferredUrl)) {
|
{
|
||||||
|
if (!string.IsNullOrEmpty(_preferredUrl))
|
||||||
|
{
|
||||||
var request = UnityWebRequest.Get(_preferredUrl);
|
var request = UnityWebRequest.Get(_preferredUrl);
|
||||||
request.timeout = (int) _checkInterval;
|
request.timeout = (int)_checkInterval;
|
||||||
yield return request.SendWebRequest();
|
yield return request.SendWebRequest();
|
||||||
|
|
||||||
if (request.result == UnityWebRequest.Result.Success) {
|
if (request.result == UnityWebRequest.Result.Success)
|
||||||
|
{
|
||||||
IsConnected = true;
|
IsConnected = true;
|
||||||
request.Dispose();
|
request.Dispose();
|
||||||
yield break;
|
yield break;
|
||||||
@@ -202,25 +230,30 @@ namespace SGModule.Net {
|
|||||||
var ops = new List<UnityWebRequestAsyncOperation>();
|
var ops = new List<UnityWebRequestAsyncOperation>();
|
||||||
var requests = new List<UnityWebRequest>();
|
var requests = new List<UnityWebRequest>();
|
||||||
|
|
||||||
foreach (var url in checkUrls) {
|
foreach (var url in checkUrls)
|
||||||
|
{
|
||||||
var req = UnityWebRequest.Get(url);
|
var req = UnityWebRequest.Get(url);
|
||||||
req.timeout = (int) _checkInterval;
|
req.timeout = (int)_checkInterval;
|
||||||
ops.Add(req.SendWebRequest());
|
ops.Add(req.SendWebRequest());
|
||||||
requests.Add(req);
|
requests.Add(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
yield return StartCoroutine(WaitForAnyRequest(ops));
|
yield return StartCoroutine(WaitForAnyRequest(ops));
|
||||||
|
|
||||||
foreach (var req in requests) {
|
foreach (var req in requests)
|
||||||
|
{
|
||||||
req.Dispose();
|
req.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 等待任意一个请求完成并返回
|
// 等待任意一个请求完成并返回
|
||||||
private IEnumerator WaitForAnyRequest(List<UnityWebRequestAsyncOperation> ops) {
|
private IEnumerator WaitForAnyRequest(List<UnityWebRequestAsyncOperation> ops)
|
||||||
while (ops.Any(op => !op.isDone)) {
|
{
|
||||||
if (ops.Any(op => op.isDone && op.webRequest.result == UnityWebRequest.Result.Success)) {
|
while (ops.Any(op => !op.isDone))
|
||||||
|
{
|
||||||
|
if (ops.Any(op => op.isDone && op.webRequest.result == UnityWebRequest.Result.Success))
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,8 +262,10 @@ namespace SGModule.Net {
|
|||||||
|
|
||||||
var successOp = ops.FirstOrDefault(op => op.webRequest.result == UnityWebRequest.Result.Success);
|
var successOp = ops.FirstOrDefault(op => op.webRequest.result == UnityWebRequest.Result.Success);
|
||||||
|
|
||||||
if (successOp == null) {
|
if (successOp == null)
|
||||||
foreach (var op in ops.Where(op => op.isDone)) {
|
{
|
||||||
|
foreach (var op in ops.Where(op => op.isDone))
|
||||||
|
{
|
||||||
Log.Net.Warning($"请求失败: {op.webRequest.url}, 错误: {op.webRequest.error}");
|
Log.Net.Warning($"请求失败: {op.webRequest.url}, 错误: {op.webRequest.error}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -240,32 +275,41 @@ namespace SGModule.Net {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 添加或删除检查 URL
|
// 添加或删除检查 URL
|
||||||
public void AddCheckUrl(string url) {
|
public void AddCheckUrl(string url)
|
||||||
if (!checkUrls.Contains(url)) {
|
{
|
||||||
|
if (!checkUrls.Contains(url))
|
||||||
|
{
|
||||||
checkUrls.Add(url);
|
checkUrls.Add(url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveCheckUrl(string url) {
|
public void RemoveCheckUrl(string url)
|
||||||
if (checkUrls.Contains(url)) {
|
{
|
||||||
|
if (checkUrls.Contains(url))
|
||||||
|
{
|
||||||
checkUrls.Remove(url);
|
checkUrls.Remove(url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddPingTarget(string ip) {
|
public void AddPingTarget(string ip)
|
||||||
if (!_pingAddresses.Contains(ip)) {
|
{
|
||||||
|
if (!_pingAddresses.Contains(ip))
|
||||||
|
{
|
||||||
_pingAddresses.Add(ip);
|
_pingAddresses.Add(ip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemovePingTarget(string ip) {
|
public void RemovePingTarget(string ip)
|
||||||
if (_pingAddresses.Contains(ip)) {
|
{
|
||||||
|
if (_pingAddresses.Contains(ip))
|
||||||
|
{
|
||||||
_pingAddresses.Remove(ip);
|
_pingAddresses.Remove(ip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 切换是否使用 Ping 检测
|
// 切换是否使用 Ping 检测
|
||||||
public void SetUsePingCheck(bool enablePing) {
|
public void SetUsePingCheck(bool enablePing)
|
||||||
|
{
|
||||||
usePingCheck = enablePing;
|
usePingCheck = enablePing;
|
||||||
#if UNITY_WEBGL
|
#if UNITY_WEBGL
|
||||||
usePingCheck = false;
|
usePingCheck = false;
|
||||||
@@ -273,8 +317,10 @@ usePingCheck = false;
|
|||||||
_checkInterval = usePingCheck ? PingInterval : WebRequestInterval;
|
_checkInterval = usePingCheck ? PingInterval : WebRequestInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool QuickNetDeviceCheck() {
|
private bool QuickNetDeviceCheck()
|
||||||
if (Application.isEditor) {
|
{
|
||||||
|
if (Application.isEditor)
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user