using Assets.Core; using Assets.Scenes.Ride.Scripts; using Assets.Scripts.Apis.Models; using Cysharp.Threading.Tasks; using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using UnityEngine; using UnityEngine.Networking; /// /// 异步线程更新ui工具类 /// public class Loom : MonoBehaviour { public static int maxThreads = 8; static int numThreads; private static Loom _current; public static Loom Current { get { Initialize(); return _current; } } //####去除Awake // void Awake() // { // _current = this; // initialized = true; // } static bool initialized; //####作为初始化方法自己调用,可在初始化场景调用一次即可 public static void Initialize() { if (!initialized) { if (!Application.isPlaying) return; initialized = true; GameObject g = new GameObject("Loom"); //####永不销毁 DontDestroyOnLoad(g); _current = g.AddComponent(); MapUDPService.Init(); MapUDPService.Send(0, App.CurrentUser.Id, new double[] { -1d, -1d }, competitionId: 0); } } private List _actions = new List(); public struct DelayedQueueItem { public float time; public Action action; } private List _delayed = new List(); List _currentDelayed = new List(); public static void QueueOnMainThread(Action action) { QueueOnMainThread(action, 0f); } public static void QueueOnMainThread(Action action, float time) { if (time != 0) { if (Current != null) { lock (Current._delayed) { Current._delayed.Add(new DelayedQueueItem { time = Time.time + time, action = action }); } } } else { if (Current != null) { lock (Current._actions) { Current._actions.Add(action); } } } } public static Thread RunAsync(Action a) { Initialize(); while (numThreads >= maxThreads) { Thread.Sleep(1); } Interlocked.Increment(ref numThreads); ThreadPool.QueueUserWorkItem(RunAction, a); return null; } private static void RunAction(object action) { try { ((Action)action)(); } catch { } finally { Interlocked.Decrement(ref numThreads); } } void OnDisable() { if (_current == this) { _current = null; } } List _currentActions = new List(); // Update is called once per frame void Update() { lock (_actions) { _currentActions.Clear(); _currentActions.AddRange(_actions); _actions.Clear(); } foreach (var a in _currentActions) { a(); } lock (_delayed) { _currentDelayed.Clear(); _currentDelayed.AddRange(_delayed.Where(d => d.time <= Time.time)); foreach (var item in _currentDelayed) _delayed.Remove(item); } foreach (var delayed in _currentDelayed) { delayed.action(); } } public static void Dispose() { if (_current != null) { initialized = false; DestroyImmediate(_current.gameObject); _current = null; } } public static Dictionary DownloadStack = new Dictionary(); public static async Task DownloadLoadARDataAndVideo(MapRoute route,IProgress progress) { DownloadStack.Add(route.FileName, new DownloadInfo(route.FileName,route.Name,0, route.Url)); var path = PFConstants.VideoFolder; var localPath = PFConstants.ARFolder; var arDataPath = route.ARConfig; var videoRoute = route.VideoRoute; var cancelToken = new CancellationTokenSource(); var dataPath = $"{localPath}/{route.Id}"; Helper.CreateDirectoryIfNotExsit(dataPath); Helper.CreateDirectoryIfNotExsit(dataPath); await Loom.DownloadToFileAsync(arDataPath, $"{dataPath}/{route.Id}.json"); await Loom.DownloadToFileAsync(videoRoute, $"{dataPath}/route-{route.Id}.json"); await Loom.DownloadToFileAsync(route.Url, $"{path}/{route.FileName}", progress, cancelToken); } /// /// 下载文件到本地(持续存入磁盘减少内存占用) /// /// 文件连接 /// 本地文件全路径 /// 下载进度 public static async UniTask DownloadToFileAsync(string downloadUrl, string fullPath, IProgress progress = null, CancellationTokenSource cancellation = default(CancellationTokenSource)) { var dh = new DownloadHandlerFile(fullPath) { removeFileOnAbort = true }; var request = UnityWebRequest.Get(downloadUrl); request.method = UnityWebRequest.kHttpVerbGET; request.downloadHandler = dh; return await request.SendWebRequest().ToUniTask(progress, PlayerLoopTiming.Update, (cancellation?.Token ?? default(CancellationToken))); } }